how to dynamically resize text in flutter?

There are two ways to deal with do this.

  1. Utilizing FittedBox
  2. Utilizing TextPainter (figure width with text Painter and update textual style )

Utilizing FitterdBox, Wrap the Text Widget into FittedBox Widget with fitWidth boundary.

Container(
  width: 250,
  height: 20,
  child:  FittedBox(fit:BoxFit.fitWidth,
      child: Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."),
  ),
),

The downside of the above methodology is that we don’t have power over the base and greatest text dimension.

To stay away from above downside. We can simply use Text Painter and ascertain he proper scale factor like after:

class AdaptableText extends StatelessWidget {
  final String text;
  final TextStyle style;
  final TextAlign textAlign;
  final TextDirection textDirection;
  final double minimumFontScale;
  final TextOverflow textOverflow;
  const AdaptableText(this.text,
      {this.style,
        this.textAlign = TextAlign.left,
        this.textDirection = TextDirection.ltr,
        this.minimumFontScale = 0.5,
        this.textOverflow = TextOverflow.ellipsis,
        Key key})
      : super(key: key);

  @override
  Widget build(BuildContext context) {

    TextPainter _painter = TextPainter(
        text: TextSpan(text: this.text, style: this.style),
        textAlign: this.textAlign,
        textScaleFactor: 1,
        maxLines: 100,
        textDirection: this.textDirection);

    return LayoutBuilder(
      builder: (context, constraints) {
        _painter.layout(maxWidth: constraints.maxWidth);
        double textScaleFactor = 1;

        if (_painter.height > constraints.maxHeight) { //
          print('${_painter.size}');
           _painter.textScaleFactor  = minimumFontScale;
           _painter.layout(maxWidth: constraints.maxWidth);
          print('${_painter.size}');

           if (_painter.height > constraints.maxHeight) { //
             //even minimum does not fit render it with minimum size
             print("Using minimum set font");
             textScaleFactor = minimumFontScale;
           } else if (minimumFontScale < 1) {
             //binary search for valid Scale factor
             int h = 100; //why 100, strpping 0.01 scale factor to get exact fit value
             int l =   (minimumFontScale * 100).toInt();
             while (h > l) {
               int mid = (l + (h - l) / 2).toInt();
               double newScale = mid.toDouble()/100.0;
               _painter.textScaleFactor  = newScale;
               _painter.layout(maxWidth: constraints.maxWidth);

               if (_painter.height > constraints.maxHeight) { //
                  h = mid - 1;
               } else {
                  l = mid + 1;
               }
               if  (h <= l) {
                 print('${_painter.size}');
                 textScaleFactor = newScale - 0.01;
                 _painter.textScaleFactor  = newScale;
                 _painter.layout(maxWidth: constraints.maxWidth);
                 break;
               }


             }
           }
        }

        return Text(
          this.text,
          style: this.style,
          textAlign: this.textAlign,
          textDirection: this.textDirection,
          textScaleFactor: textScaleFactor,
          maxLines: 100,
          overflow: textOverflow,
        );
      },
    );
  }
}

Demo and Results:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  MyApp({Key key}) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String mediumSizeText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit. ";
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('ExpandableText'),
        ),
        body: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text('Normal Text'),
            Text(mediumSizeText),
            SizedBox(
              height: 20,
            ),
            Text('Container(250*20) Normal Text:'),
            Container(
              width: 250,
              height: 20,
              color: Colors.green,
              child: Text(
                mediumSizeText,
                overflow: TextOverflow.ellipsis,
              ),
            ),
            SizedBox(
              height: 20,
            ),
            Text('Container(250*20) => sizebox => Text:'),
            Container(
              width: 250,
              height: 20,
              color: Colors.green,
              child:  FittedBox(fit:BoxFit.fitWidth,
                  child: Text(mediumSizeText, maxLines: 100,),
              ),
            ),
            Text('Container(250*20) => AdaptableText => Text:'),
            Container(
              width: 250,
              height: 20,
              color: Colors.green,
                child: AdaptableText(mediumSizeText,style: TextStyle()),
            ),
          ],
        ),
      ),
    );
  }
}


class AdaptableText extends StatelessWidget {
  final String text;
  final TextStyle style;
  final TextAlign textAlign;
  final TextDirection textDirection;
  final double minimumFontScale;
  final TextOverflow textOverflow;
  const AdaptableText(this.text,
      {this.style,
        this.textAlign = TextAlign.left,
        this.textDirection = TextDirection.ltr,
        this.minimumFontScale = 0.5,
        this.textOverflow = TextOverflow.ellipsis,
        Key key})
      : super(key: key);

  @override
  Widget build(BuildContext context) {

    TextPainter _painter = TextPainter(
        text: TextSpan(text: this.text, style: this.style),
        textAlign: this.textAlign,
        textScaleFactor: 1,
        maxLines: 100,
        textDirection: this.textDirection);

    return LayoutBuilder(
      builder: (context, constraints) {
        _painter.layout(maxWidth: constraints.maxWidth);
        double textScaleFactor = 1;

        if (_painter.height > constraints.maxHeight) { //
          print('${_painter.size}');
           _painter.textScaleFactor  = minimumFontScale;
           _painter.layout(maxWidth: constraints.maxWidth);
          print('${_painter.size}');

           if (_painter.height > constraints.maxHeight) { //
             //even minimum does not fit render it with minimum size
             print("Using minimum set font");
             textScaleFactor = minimumFontScale;
           } else if (minimumFontScale < 1) {
             //binary search for valid Scale factor
             int h = 100;
             int l =   (minimumFontScale * 100).toInt();
             while (h > l) {
               int mid = (l + (h - l) / 2).toInt();
               double newScale = mid.toDouble()/100.0;
               _painter.textScaleFactor  = newScale;
               _painter.layout(maxWidth: constraints.maxWidth);

               if (_painter.height > constraints.maxHeight) { //
                  h = mid - 1;
               } else {
                  l = mid + 1;
               }
               if  (h <= l) {
                 print('${_painter.size}');
                 textScaleFactor = newScale - 0.01;
                 _painter.textScaleFactor  = newScale;
                 _painter.layout(maxWidth: constraints.maxWidth);
                 break;
               }


             }
           }
        }

        return Text(
          this.text,
          style: this.style,
          textAlign: this.textAlign,
          textDirection: this.textDirection,
          textScaleFactor: textScaleFactor,
          maxLines: 100,
          overflow: textOverflow,
        );
      },
    );
  }
}
Image for post
sized, small, large text

Thanks for being with us on a Flutter Journey!!!

Leave a Comment