Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 338 Vote(s) - 3.49 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How can I get the size of the Text widget in Flutter

#1
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.

So, I need to get the width and height of my Text Widget before `Widget build(BuildContext context)`.


Actually, I am simulating the chat bubble effect like iOS message using flutter. Here is the iOS version tutorial. [Creating a Chat Bubble][1] .


The core code below:

let label = UILabel()
label.numberOfLines = 0
label.font = UIFont.systemFont(ofSize: 18)
label.textColor = .white
label.text = text

let constraintRect = CGSize(width: 0.66 * view.frame.width,
height: .greatestFiniteMagnitude)
let boundingBox = text.boundingRect(with: constraintRect,
options: .usesLineFragmentOrigin,
attributes: [.font: label.font],
context: nil)
label.frame.size = CGSize(width: ceil(boundingBox.width),
height: ceil(boundingBox.height))

let bubbleSize = CGSize(width: label.frame.width + 28,
height: label.frame.height + 20)

let width = bubbleSize.width
let height = bubbleSize.height



=========================================
**SOLUTION**
Here is my solution.

bubble.dart:

// Define a CustomPainter to paint the bubble background.
class BubblePainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final Paint paint = Paint()
..color = Color(0xff188aff)
..style = PaintingStyle.fill;
final Path bubble = Path()
..moveTo(size.width - 22.0, size.height)
..lineTo(17.0, size.height)
..cubicTo(
7.61, size.height, 0.0, size.height - 7.61, 0.0, size.height - 17.0)
..lineTo(0.0, 17.0)
..cubicTo(0.0, 7.61, 7.61, 0.0, 17.0, 0.0)
..lineTo(size.width - 21, 0.0)
..cubicTo(size.width - 11.61, 0.0, size.width - 4.0, 7.61,
size.width - 4.0, 17.0)
..lineTo(size.width - 4.0, size.height - 11.0)
..cubicTo(size.width - 4.0, size.height - 1.0, size.width, size.height,
size.width, size.height)
..lineTo(size.width + 0.05, size.height - 0.01)
..cubicTo(size.width - 4.07, size.height + 0.43, size.width - 8.16,
size.height - 1.06, size.width - 11.04, size.height - 4.04)
..cubicTo(size.width - 16.0, size.height, size.width - 19.0, size.height,
size.width - 22.0, size.height)
..close();
canvas.drawPath(bubble, paint);
}

@override
bool shouldRepaint(BubblePainter oldPainter) => true;
}

// This is my custom RenderObject.
class BubbleMessage extends SingleChildRenderObjectWidget {
BubbleMessage({
Key key,
this.painter,
Widget child,
}) : super(key: key, child: child);

final CustomPainter painter;

@override
RenderCustomPaint createRenderObject(BuildContext context) {
return RenderCustomPaint(
painter: painter,
);
}

@override
void updateRenderObject(
BuildContext context, RenderCustomPaint renderObject) {
renderObject..painter = painter;
}
}

Use the `BubbleMessage` Widget like this:

import 'bubble.dart'

...code ...

BubbleMessage(
painter: BubblePainter(),
child: Container(
constraints: BoxConstraints(
maxWidth: 250.0,
minWidth: 50.0,
),
padding: EdgeInsets.symmetric(horizontal: 15.0, vertical: 6.0),
child: Text(
'your text variable',
softWrap: true,
style: TextStyle(
fontSize: 16.0,
),
),
),
),

...code ...

The bubble effect:

[![enter image description here][2]][2]


[1]:

[To see links please register here]

[2]:
Reply

#2
A simple example:

For how it works see inline comments.

Inspiration from

[To see links please register here]


[![enter image description here][1]][1]

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<MyHomePage> {
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: <Widget>[
SizedBox(
height: mq.size.height,
width: 240.0,
child: ListView(
padding: EdgeInsets.all(4.0),
children: <Widget>[
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<Bubble> {
@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}'),
);
}

[![enter image description here][2]][2]


[1]:

[2]:
Reply

#3
from inspiring of the Günter Zöchbauer

List<bool> _calcLastLineEnd(String msg) {
// self-defined constraint
final constraints = BoxConstraints(
maxWidth: 800.0, // maxwidth calculated
minHeight: 30.0,
minWidth: 80.0,
);
final richTextWidget =
Text.rich(TextSpan(text: msg)).build(context) as RichText;
final renderObject = richTextWidget.createRenderObject(context);
renderObject.layout(constraints);
final boxes = renderObject.getBoxesForSelection(TextSelection(
baseOffset: 0, extentOffset: TextSpan(text: msg).toPlainText().length));
bool needPadding = false, needNextline = false;
if (boxes.length < 2 && boxes.last.right < 630) needPadding = true;
if (boxes.length < 2 && boxes.last.right > 630) needNextline = true;
if (boxes.length > 1 && boxes.last.right > 630) needNextline = true;
return [needPadding, needNextline];
}
Reply

#4
I found another method without using the `context`:

final constraints = BoxConstraints(
maxWidth: 800.0, // maxwidth calculated
minHeight: 0.0,
minWidth: 0.0,
);

RenderParagraph renderParagraph = RenderParagraph(
TextSpan(
text: text,
style: TextStyle(
fontSize: fontSize,
),
),
textDirection: ui.TextDirection.ltr,
maxLines: 1,
);
renderParagraph.layout(constraints);
double textlen = renderParagraph.getMinIntrinsicWidth(fontSize).ceilToDouble();


Reply

#5
My apologies.
**This is not a direct answer on the topic's question!**
But If someone needs to get the size of a Text widget — this method can help. It helped me in creation of custom menu widget.

class TextSized extends StatelessWidget {
const TextSized({Key key}) : super(key: key);

@override
Widget build(BuildContext context) {
final String text = "Text in one line";
final TextStyle textStyle = TextStyle(
fontSize: 30,
color: Colors.white,
);
final Size txtSize = _textSize(text, textStyle);

// This kind of use - meaningless. It's just an example.
return Container(
color: Colors.blueGrey,
width: txtSize.width,
height: txtSize.height,
child: Text(
text,
style: textStyle,
softWrap: false,
overflow: TextOverflow.clip,
maxLines: 1,
),
);
}

// Here it is!
Size _textSize(String text, TextStyle style) {
final TextPainter textPainter = TextPainter(
text: TextSpan(text: text, style: style), maxLines: 1, textDirection: TextDirection.ltr)
..layout(minWidth: 0, maxWidth: double.infinity);
return textPainter.size;
}
}
Reply

#6
Problem with other answers is that if you use `Text` widget to display your text and constraint it with measurements result without considering default font family and scale factor, then you will get wrong results because `Text` widget is using device's `textScaleFactor` by default and passing it to `RichText` widget inside of it. This is the correct code to measure text size:

final Size size = (TextPainter(
text: TextSpan(text: text, style: textStyle),
maxLines: 1,
textScaleFactor: MediaQuery.of(context).textScaleFactor,
textDirection: TextDirection.ltr)
..layout())
.size;
Reply

#7
Modified variant of Günter Zöchbauer solution wich can use text overflow

```
TextBox textBox(BuildContext context, String text, TextStyle textStyle,
int maxLines, TextOverflow overflow, BoxConstraints constraints) {
final textSpan = TextSpan(
text: text,
style: textStyle,
);
final richTextWidget = Text.rich(
textSpan,
maxLines: maxLines,
overflow: overflow,
).build(context) as RichText;
final renderObject = richTextWidget.createRenderObject(context);
renderObject.layout(constraints);
final boxesForSelection = renderObject.getBoxesForSelection(TextSelection(
baseOffset: 0, extentOffset: richTextWidget.text.toPlainText().length));
if (boxesForSelection.length == 0)
return TextBox.fromLTRBD(0.0, 0.0, 0.0, 0.0, TextDirection.ltr);
final List<double> widths = List();
boxesForSelection.forEach((box) {
widths.add(box.right);
});
widths.sort((a, b) => a.compareTo(b));
return TextBox.fromLTRBD(
0.0, 0.0, widths.last, boxesForSelection.last.bottom, TextDirection.ltr);
}
```
Reply

#8
I just discovered that line breaks can break a couple of approaches here, so just for completeness I solved it very hacky like this:

1. Replace all `\n` before doing the calculation: `text.replace('\n', '')`
2. Get number of line breaks: `text.split('\n').length`
3. Add this to the number of lines, before multiplying the line count with the line height

Also keep in mind that you have to account for any eventual padding, when calculating the number of lines ` (sizeFull.width / (mediaQuery.size.width - PADDING)).ceil()`

Full Example:

```Dart
Widget build(BuildContext context) {
final mediaQuery = MediaQuery.of(context);

final Size sizeFull = (TextPainter(
text: TextSpan(
text: text.replaceAll('\n', ''),
style: textStyle,
),
textScaleFactor: mediaQuery.textScaleFactor,
textDirection: TextDirection.ltr,
)..layout())
.size;


final numberOfLinebreaks = text.split('\n').length;


final numberOfLines =
(sizeFull.width / (mediaQuery.size.width)).ceil() +
numberOfLinebreaks;

return Container(
height: sizeFull.height * numberOfLines,
child: Text(text),
);
}
Reply

#9
Multiline text height (modified variant of Dmitry_Kovalov)

import 'package:flutter/cupertino.dart';

extension StringExtension on String {
double textHeight(TextStyle style, double textWidth) {
final TextPainter textPainter = TextPainter(
text: TextSpan(text: this, style: style),
textDirection: TextDirection.ltr,
maxLines: 1,
)..layout(minWidth: 0, maxWidth: double.infinity);

final countLines = (textPainter.size.width / textWidth).ceil();
final height = countLines * textPainter.size.height;
return height;
}
}

You may need to `import 'dart:ui' as ui;` if `ltr` is not visible. Then `textDirection: ui.TextDirection.ltr`
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through