'Flutter how to create responsive Text widget?

I'm facing a problem with responsive texts. In my app are different text font sizes and I need to do them responsive for different screen sizes (only phones and device orientation portrait). I also added textScaleFactor: 1.0 to my MaterialApp like this:

    builder: (context, widget) {
      return MediaQuery(
        child: widget,
        data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
      );
    },

but it does not helped much. I tried also calculate the font size with MediaQuery.of(context).size.width, but I think it dangerous and wrong. I want it to be as close as possible to the design that was given to me, but I started to lose it on this steps. Is there any solution for this? How you achieve this?

Thank you in advance.



Solution 1:[1]

you can use this plugin flutter_screenutil. It is a flutter plugin for adapting screen and font size.Let your UI display a reasonable layout on different screen sizes!

Initialize and set the fit size and font size to scale according to the system's "font size" accessibility option # Please set the width and height of the design draft before use, the width and height of the design draft (unit px). Be sure to set the page in the MaterialApp's home(ie the entry file, just set it once) to ensure that the fit size is set before each use:

//fill in the screen size of the device in the design

//default value : width : 1080px , height:1920px , 
allowFontScaling:false
ScreenUtil.instance = ScreenUtil.getInstance()..init(context);

//If the design is based on the size of the iPhone6 ??(iPhone6 ??750*1334)
ScreenUtil.instance = ScreenUtil(width: 750, height: 
1334)..init(context);

//If you wang to set the font size is scaled according to the system's 
"font size" assist option
ScreenUtil.instance = ScreenUtil(width: 750, height: 1334, 
allowFontScaling: true)..init(context);

Use? # Adapt screen size? # Pass the px size of the design draft?

Adapted to screen width: ScreenUtil.getInstance().setWidth(540),

Adapted to screen height: ScreenUtil.getInstance().setHeight(200),

You can also use ScreenUtil() instead of ScreenUtil.getInstance(), for example:ScreenUtil().setHeight(200)

Note

Height is also adapted according to setWidth to ensure no deformation (when you want a square)

setHeight method is mainly adapted in height, you want to control the height and actuality of a screen on the UIUsed when the same is displayed.

//for example:
//rectangle
Container(
       width: ScreenUtil.getInstance().setWidth(375),
       height: ScreenUtil.getInstance().setHeight(200),
       ...
        ),

////If you want to display a square:
Container(
       width: ScreenUtil.getInstance().setWidth(300),
       height: ScreenUtil.getInstance().setWidth(300),
        ),

Adapter font:

//Incoming font size?the unit is pixel, fonts will not scale to 
respect Text Size accessibility settings
//(AllowallowFontScaling when initializing ScreenUtil)
ScreenUtil.getInstance().setSp(28)    

//Incoming font size?the unit is pixel?fonts will scale to respect Text 
Size accessibility settings
//(If somewhere does not follow the global allowFontScaling setting)
ScreenUtil(allowFontScaling: true).setSp(28)  

//for example:

Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text(
                'My font size is 24px on the design draft and will not change with the system.',
                style: TextStyle(
                  color: Colors.black,
                  fontSize: ScreenUtil.getInstance().setSp(24),
                )),
            Text(
                'My font size is 24px on the design draft and will change with the system.',
                style: TextStyle(
                  color: Colors.black,
                  fontSize: ScreenUtil(allowFontScaling: true).setSp(24),
                )),
          ],
        )

Other related apis?

ScreenUtil.pixelRatio       //Device pixel density
ScreenUtil.screenWidth      //Device width
ScreenUtil.screenHeight     //Device height
ScreenUtil.bottomBarHeight  //Bottom safe zone distance, suitable for buttons with full screen
ScreenUtil.statusBarHeight  //Status bar height , Notch will be higher Unit px
ScreenUtil.textScaleFactory //System font scaling factor

ScreenUtil.getInstance().scaleWidth //Ratio of actual width dp to design draft px
ScreenUtil.getInstance().scaleHeight //Ratio of actual height dp to design draft px

Solution 2:[2]

try this: you get the adaptive text size according to different screen sizes

    class AdaptiveTextSize {
      const AdaptiveTextSize();

      getadaptiveTextSize(BuildContext context, dynamic value) {
    // 720 is medium screen height
        return (value / 720) * MediaQuery.of(context).size.height;
      }
    }

use case :

                 Text("Paras Arora",style: TextStyle(fontSize: 
                 AdaptiveTextSize().getadaptiveTextSize(context, 20)),

Solution 3:[3]

class SizeConfig {
  static MediaQueryData _mediaQueryData;
  static double screenWidth;
  static double screenHeight;
  static double blockSizeHorizontal;
  static double blockSizeVertical;

  void init(BuildContext context) {
    _mediaQueryData = MediaQuery.of(context);
    screenWidth = _mediaQueryData.size.width;
    screenHeight = _mediaQueryData.size.height;
    blockSizeHorizontal = screenWidth / 100;
    blockSizeVertical = screenHeight / 100;
  }
}

SizeConfig().init(context); add this after widget build and use style: TextStyle(fontSize: 2 * SizeConfig.blockSizeVertical,),

Multiply with your desired number, try at least one time. I have attached screen shots.

My solution:
My solution

Other Solutions:
Other Solutions

Solution 4:[4]

You can get the constraints from LayoutBuilder and pass that to the ScreenUtil.init() as shown in the following code.

return LayoutBuilder(
      builder: (BuildContext context, BoxConstraints constraints) {
        return OrientationBuilder(
          builder: (BuildContext context, Orientation orientation) {
            ScreenUtil.init(
              constraints,
              designSize: orientation == Orientation.portrait
                  ? (Platform.isAndroid || Platform.isIOS) ? Size(450.0, 870.0) : 
                    Size(705.0, 1366.0)
                  : (Platform.isAndroid || Platform.isIOS) ? Size(870.0, 450.0) : 
                    Size(1366.0, 705.0),
              allowFontScaling: false,
            );
            return MaterialApp(
              theme: ThemeData(
                textTheme: Theme.of(context).textTheme.copyWith(
                      headline6: TextStyle(
                        fontSize: 24.sp,
                      ),
                    ),
              ),
              home: HomeScreen(),
            );
          },
        );
      },
    );

We can check orientation == Orientation.portrait to set width & height of the screen in which we are designing. To support both orientations just inverse the width & height values accordingly.

You can also check Platform.isAndroid || Platform.isIOS & give the width & height of mobile devices.

Solution 5:[5]

You can try this:

final size = MediaQuery.of(context).size;

You could apply the same concept, in this case for the container:

Container(
            width: size.width * 0.85,
           ...
)

Solution 6:[6]

I would like to answer to my question. In past months I was using flutter_screenutil

But as I mentioned in the comments, I need to add responsive fonts sizes in the theme, so I customized the flutter_screenutil package to use it in there. I think it is working perfect. I already used this solution in couple of projects and have not any trouble.

import 'package:flutter/material.dart';

class CustomScreenUtil {
  static CustomScreenUtil _instance;
  static const int defaultWidth = 1080;
  static const int defaultHeight = 1920;

  /// Size of the phone in UI Design , px
  num uiWidthPx;
  num uiHeightPx;

  /// allowFontScaling Specifies whether fonts should scale to respect Text Size accessibility settings. The default is false.
  bool allowFontScaling;

  static double _screenWidth;
  static double _screenHeight;
  static double _pixelRatio;
  static double _statusBarHeight;
  static double _bottomBarHeight;
  static double _textScaleFactor;

  CustomScreenUtil._();

  factory CustomScreenUtil() {
    return _instance;
  }

  static void init({num width = defaultWidth,
    num height = defaultHeight,
    bool allowFontScaling = false}) {
    if (_instance == null) {
      _instance = CustomScreenUtil._();
    }
    _instance.uiWidthPx = width;
    _instance.uiHeightPx = height;
    _instance.allowFontScaling = allowFontScaling;

    _pixelRatio = WidgetsBinding.instance.window.devicePixelRatio;
    _screenWidth = WidgetsBinding.instance.window.physicalSize.width;
    _screenHeight = WidgetsBinding.instance.window.physicalSize.height;
    _statusBarHeight = WidgetsBinding.instance.window.padding.top;
    _bottomBarHeight = WidgetsBinding.instance.window.padding.bottom;
    _textScaleFactor = WidgetsBinding.instance.window.textScaleFactor;
  }

  /// The number of font pixels for each logical pixel.
  static double get textScaleFactor => _textScaleFactor;

  /// The size of the media in logical pixels (e.g, the size of the screen).
  static double get pixelRatio => _pixelRatio;

  /// The horizontal extent of this size.
  static double get screenWidthDp => _screenWidth;

  ///The vertical extent of this size. dp
  static double get screenHeightDp => _screenHeight;

  /// The vertical extent of this size. px
  static double get screenWidth => _screenWidth * _pixelRatio;

  /// The vertical extent of this size. px
  static double get screenHeight => _screenHeight * _pixelRatio;

  /// The offset from the top
  static double get statusBarHeight => _statusBarHeight;

  /// The offset from the bottom.
  static double get bottomBarHeight => _bottomBarHeight;

  /// The ratio of the actual dp to the design draft px
  double get scaleWidth => _screenWidth / uiWidthPx;

  double get scaleHeight => _screenHeight / uiHeightPx;

  double get scaleText => scaleWidth;

  /// Adapted to the device width of the UI Design.
  /// Height can also be adapted according to this to ensure no deformation ,
  /// if you want a square
  num setWidth(num width) => width * scaleWidth;

  /// Highly adaptable to the device according to UI Design
  /// It is recommended to use this method to achieve a high degree of adaptation
  /// when it is found that one screen in the UI design
  /// does not match the current style effect, or if there is a difference in shape.
  num setHeight(num height) => height * scaleHeight;

  ///Font size adaptation method
  ///@param [fontSize] The size of the font on the UI design, in px.
  ///@param [allowFontScaling]
  num setSp(num fontSize, {bool allowFontScalingSelf}) =>
      allowFontScalingSelf == null
          ? (allowFontScaling
          ? (fontSize * scaleText)
          : ((fontSize * scaleText) / _textScaleFactor))
          : (allowFontScalingSelf
          ? (fontSize * scaleText)
          : ((fontSize * scaleText) / _textScaleFactor));
}

Now screen util using his sizes from WidgetsBinding.instance.window not from MediaQuery and now we can use it without context like this:

_screenUtil = CustomScreenUtil();
ThemeData(
        primaryTextTheme: TextTheme(
          bodyText1: TextStyle(
            fontSize: _screenUtil.setSp(12),
          )
        ))

I don't know if this is the most solution but I'm working like this

Solution 7:[7]

For the Font Size Similar to phone size of app :

MaterialApp( home: MediaQuery(data:MediaQuery.of(context).copyWith(textScaleFactor: 1.2), child: HomePage()) );

For ListTile_Subtitle :

Text('Your Text' , textScaleFactor:1.0)

NOTE : Here , 1.2 in normal text = 1.2 x (the_FontSize_of_device) & for ListTile_Subtitle , we need smaller than normal font size , so , we control it with Text Widget textScaleFactor argument , which indicates here : 1x(the_FontSize_of_device),

Similar if You need Big text than normal font size of device , than , Text('aaaa' , textScaleFactor:2)

Solution 8:[8]

LayoutBuilder(
builder:(context,constraints){
return Text("this is responsive text",
   style:TextStyle
(fontSize:constraints.maxWidth*the percentage of your text));
//("this is how to calculate //    percentage of fontsize"
//    e.g "fontSize/total Width*100" then for example i recived the percentage on // 
//  calculator"3.45" then multiply the maxWidth with 0.0345)
   }
  );


)

Solution 9:[9]

Do this!

const Expanded(
    child: Text(
         "Your text.",
    overflow: TextOverflow.visible,
    maxLines: 5,
    softWrap: true,
    style: TextStyle(
    fontSize: 10,
    fontWeight: FontWeight.normal,
   ),
   textAlign: TextAlign.start,
 ),
),

Solution 10:[10]

1. First Solution

You can use auto_size_text package.

2. Second Solution enter image description here

A work around without the package and if you prefer using a custom theme:

get the width

    @override
  Widget build(BuildContext context) {
    double width = MediaQuery.of(context).size.width;
     return Container(...

create your custom ThemeData i.e for light and dark in you theme_provider class

static ThemeData dark() {
return ThemeData(
  textTheme: const TextTheme(
   bodyText2:
        TextStyle(color: Colors.white70, fontWeight: FontWeight.w300)...

Finally, edit your Text widget with different font sizes for different screens. You can use screen height as well...

Text( 
    widget.featuredModel.eventTitle,
    style: Theme.of(context).textTheme.bodyText2!
   .copyWith(  fontSize: width >= 1201
                          ? 22
                          : width >= 601
                              ? 20
                              : width >= 400
                                  ? 16
                                  : 14),
                ),