How do I auto scale down a font in a Text widget to fit the max number of lines?
you can use the auto text package
https://pub.dartlang.org/packages/auto_size_text
after install it, just replace all of 'Text' to 'AutoSizeText' and you will find every things will be good :)
We got 2 ready-to-use solutions to this depending on the constraints you want to have.
1. Scale only
This solution works if you like how the layout looks on some reference screen size, want to treat the text area as a box and just scale up or down the entire box given other sized screens.
Take a reference screen. Lay everything out as intended. Find out the size of the box containing the text (by showing the render tree by pressing 't' during debug for instance). Then wrap the text containing box with a SizedBox
of the same size as measured. Then wrap that with your FittedBox
.
The restriction is basically that your text is laid out exactly the same way on all screens and you'll have the same aspect ratio for the text box.
2. Multiple references
Given a parent with variable size, first use a LayoutBuilder
to get the parent's size during runtime, and then manually adjust the font size in the child text widget to make sure it fits.
The text layout is more fluid and the containing box can have different aspect ratios, but you'd have to check on as many screens sizes as the font size switches you have. Though it's easy to make sure that the text doesn't overflow at any screen size using widget tests
We can also create more complex but automatic means if there are more concrete examples of generalized use cases involving dependent font scaling
An easy drop-in solution is to use FittedBox
with fit: BoxFit.scaleDown
:
Container(
width: 100.0,
child: FittedBox(
fit: BoxFit.scaleDown,
// Optionally apply `alignment` to position the text inside the box:
//alignment: Alignment.topRight,
child: SizedBox(
child: Text('\$1,299.99'),
)
)
This happened in my app:
I solved by calculating the maximum number of chars shown in one line and reducing dynamically the Text FontSize if its string length is greater.
Get the char width of your text
First of all, I calculated the width of every char shown.
For doing that I needed the effective container width and the number of chars shown.
To get the screen width (that actually is the container width), I put my Text widget inside a LayoutBuilder
:
new LayoutBuilder(builder: (context, constraint) {
//screen width got from the LayoutBuilder
double maxWidth = constraint.biggest.width;
//I'm going to change this dinamically
double fontSize = 33.0;
//return my widget
return new Text(
_brand.name,
maxLines: 1,
style: new TextStyle(fontSize: fontSize),
);
}
To get the chars shown before a new line, I put a big string in the Text and I manually counted how many chars were shown in one line. I put this value in a const (maxCharInOneLine
) and then I was able to calculate the single char width: I divided the maximum witdh by maxCharInOneLine
:
new LayoutBuilder(builder: (context, constraint) {
//screen width got from the LayoutBuilder
double maxWidth = constraint.biggest.width;
//chars shown manually counted
const int maxCharInOneLine = 17;
//single char width
int charWidth = (maxWidth / maxCharInOneLine).toInt();
//TO RUN IN DEBUG MODE
print("Char size with this screen and Text's TextStyle: " + charWidth.toString());
...
}
I runned the code above in the debug mode in order to get the charSize
value, then I put is in a const and I removed that code that is useless at runtime.
Change dynamically the font
Now, with a constant char width and a variable container width (got from the LayoutBuilder
) you can have every time the maximum number of chars that fits in one line.
new LayoutBuilder(builder: (context, constraint) {
const int charWidth=16;
//screen width got from the LayoutBuilder
double maxWidth = constraint.biggest.width;
//dinamically get the char number that fits in one line with this screen
int charsPerLine = (maxWidth / charWidth).toInt();
//if it doesn't fit in a line, reduce the fontSize
double fontSize = (_brand.name.length <= charsPerLine) ? 33.0 : 23.0;
return new Text(
_brand.name,
maxLines: 1,
style: new TextStyle(fontSize: fontSize),
);
}
The result:
My solution is not the best, but it works well in my case.
I'd like to get feedbacks. :)
EDIT Aug 2020: You can now simply use the library AutoSizeText