How can I get the size of the Text Widget in flutter

前端 未结 5 734
不思量自难忘°
不思量自难忘° 2020-11-29 01:19

I\'ve painted a shape for the background of my content of Text.

I want the background autoscale the Text, even the softWrap being true.

5条回答
  •  攒了一身酷
    2020-11-29 01:50

    A simple example:

    For how it works see inline comments.

    Inspiration from https://github.com/flutter/flutter/issues/23247

    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Calc Text Size',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(title: 'Calc Text Size'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State {
      static const String loremIpsum =
          'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod '
          'tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim '
          'veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea '
          'commodo consequat. Duis aute irure dolor in reprehenderit in voluptate '
          'velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint '
          'occaecat cupidatat non proident, sunt in culpa qui officia deserunt '
          'mollit anim id est laborum.';
    
      @override
      Widget build(BuildContext context) {
        final mq = MediaQuery.of(context);
        return Scaffold(
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                SizedBox(
                  height: mq.size.height,
                  width: 240.0,
                  child: ListView(
                    padding: EdgeInsets.all(4.0),
                    children: [
                      Container(
                        decoration: BoxDecoration(
                          border: Border.all(color: Colors.orange),
                        ),
                        child: Bubble(
                          text: TextSpan(
                            text: loremIpsum,
                            style: Theme.of(context).textTheme.body1,
                          ),
                        ),
                      ),
                      Container(
                        decoration: BoxDecoration(
                          border: Border.all(color: Colors.orange, width: 2.0),
                        ),
                        padding: EdgeInsets.symmetric(horizontal: 2.0),
                        child: Bubble(
                          text: TextSpan(
                            text: loremIpsum,
                            style: Theme.of(context).textTheme.body1,
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
        );
      }
    }
    
    class Bubble extends StatefulWidget {
      Bubble({@required this.text});
    
      final TextSpan text;
    
      @override
      _BubbleState createState() => new _BubbleState();
    }
    
    class _BubbleState extends State {
      @override
      Widget build(BuildContext context) {
        return LayoutBuilder(builder: (context, constraints) {
          // The text to render
          final textWidget = Text.rich(widget.text);
    
          // Calculate the left, top, bottom position of the end of the last text
          // line.
          final lastBox = _calcLastLineEnd(context, constraints);
    
          // Calculate whether the timestamp fits into the last line or if it has
          // to be positioned after the last line.
          final fitsLastLine =
              constraints.maxWidth - lastBox.right > Timestamp.size.width + 10.0;
    
          return Stack(
            children: [
              // Ensure the stack is big enough to render the text and the
              // timestamp.
              SizedBox.fromSize(
                  size: Size(
                    constraints.maxWidth,
                    (fitsLastLine ? lastBox.top : lastBox.bottom) +
                        10.0 +
                        Timestamp.size.height,
                  ),
                  child: Container()),
              // Render the text.
              textWidget,
              // Render the timestamp.
              Positioned(
                left: constraints.maxWidth - (Timestamp.size.width + 10.0),
                top: (fitsLastLine ? lastBox.top : lastBox.bottom) + 5.0,
                child: Timestamp(DateTime.now()),
              ),
            ],
          );
        });
      }
    
      // Calculate the left, top, bottom position of the end of the last text
      // line.
      TextBox _calcLastLineEnd(BuildContext context, BoxConstraints constraints) {
        final richTextWidget = Text.rich(widget.text).build(context) as RichText;
        final renderObject = richTextWidget.createRenderObject(context);
        renderObject.layout(constraints);
        final lastBox = renderObject
            .getBoxesForSelection(TextSelection(
                baseOffset: 0, extentOffset: widget.text.toPlainText().length))
            .last;
        return lastBox;
      }
    }
    
    class Timestamp extends StatelessWidget {
      Timestamp(this.timestamp);
    
      final DateTime timestamp;
    
      /// This size could be calculated similarly to the way the text size in
      /// [Bubble] is calculated instead of using magic values.
      static final Size size = Size(60.0, 25.0);
    
      @override
      Widget build(BuildContext context) => Container(
            padding: EdgeInsets.all(3.0),
            decoration: BoxDecoration(
              color: Colors.greenAccent,
              border: Border.all(color: Colors.yellow),
            ),
            child:
                Text('${timestamp.hour}:${timestamp.minute}:${timestamp.second}'),
          );
    }
    

提交回复
热议问题