How To Do Dynamic Font Size According to ScreenWidth When Specifying FontSize In ThemeData?

Viewed 2290

I need my font sizes to change depending on the width of the user's screen. I am using a file, size_config.dart, for this, which contains the method getProportionateScreenWidth() to retrieve the user screen width and do some calculations.

Because I want a light and dark UI I am creating two ThemeData classes, and have decided to do all TextStyles in it. My issue right now is that when I attempt to call the method to set the font size I get a NoSuchMethodError: The method 'toDouble' was called on null. Presumably the reason is that the ThemeData is calculated before the app startup? Thus there is no screen width to work with so I get an error. Is there an easy fix for this?

//size_config.dart
class SizeConfig {
  static MediaQueryData _mediaQueryData;
  static double screenWidth;
  static double screenHeight;
  static double defaultSize;
  static Orientation orientation;

  void init(BuildContext context) {
    _mediaQueryData = MediaQuery.of(context);
    screenWidth = _mediaQueryData.size.width;
    screenHeight = _mediaQueryData.size.height;
    orientation = _mediaQueryData.orientation;
  }
}

double getProportionateScreenWidth(double inputWidth) {
  double screenWidth = SizeConfig.screenWidth;
  // 375 is the layout width that designer use
  return (inputWidth / 375.0) * screenWidth;
}
//themes.dart
ThemeData lightTheme() {
  return ThemeData (
    textTheme: lightTextTheme()
    //and other theme stuff
  );
}

TextTheme textTheme() {
  return TextTheme(
      headline1: TextStyle(
          color: Color(0xFF000000),
          fontSize: getProportionateScreenWidth(25), //problem is with here i believe
          fontWeight: FontWeight.normal),
  );
}
//main.dart
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: lightTheme(), //instantiating theme
      initialRoute: '/onboarding',
      routes: {
        '/onboarding': (context) => OnboardingScreen(),
        '/home': (context) => HomeScreen(),
        '/assistant': (context) => AssistantScreen(),
      },
    );
  }
}
//body.dart (where headline1 is being used) don't believe problem is here as this is not even rendered in upon start of the app (an onBoarding screen comes before it named routing is used to navigate the separate screens)
Text(
  'Hello,',
  textAlign: TextAlign.left,
  style: Theme.of(context).textTheme.headline1,
),
//Error message
════════ Exception caught by widgets library ═══════════════════════════════════
The following NoSuchMethodError was thrown building MyApp(dirty):
The method 'toDouble' was called on null.
Receiver: null
Tried calling: toDouble()

The relevant error-causing widget was
    MyApp 
package:dash/main.dart:17
When the exception was thrown, this was the stack
#0      Object.noSuchMethod  (dart:core-patch/object_patch.dart:51:5)
#1      double.*  (dart:core-patch/double.dart:36:23)
#2      getProportionateScreenWidth 
package:dash/size_config.dart:29
#3      textTheme 
package:dash/themes.dart:35
#4      lightTheme 
package:dash/themes.dart:11
...
════════════════════════════════════════════════════════════════════════════════

Help is greatly appreciated!

3 Answers

I use media query for this Using MediaQuery.of(context).size.height/100 * 5, I first convert the device height into percentage and multiply it by some no. you can do that too and can create a separate class for dimensions. My dimensions class looks like this.

class Dimensions {
  static double boxWidth;
  static double boxHeight;

  Dimensions(context) {
    boxHeight = MediaQuery.of(context).size.height / 100;
    boxWidth = MediaQuery.of(context).size.width / 100;
  }
}

then I can call Dimensions.box height * (someone) to set any dynamically changing constraints, But remember to initialize this dimension class before any build method.
Just like below.

  @override
  Widget build(BuildContext context) {
    Dimensions(context);   //initializing context
    return Material(
      child: Center(
        child: Text(
          "This is Splash Screen",
          style: TextStyle(fontSize: Dimensions.boxHeight * 5), //Using dynamic sizing.
        ),
      ),
    );
  }

you can also check this package flutter_screenutil

A flutter plugin for adapting screen and font size.Guaranteed to look good on different models

A flutter plugin for adapting screen and font size.Let your UI display a reasonable layout on different screen sizes!

They are still continuously developing it and it is very easy to use.

//main.dart
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
   
     SizeConfig().init(context); // add this line for initialization

    return MaterialApp(
      title: 'Flutter Demo',
      theme: lightTheme(), //instantiating theme
      initialRoute: '/onboarding',
      routes: {
        '/onboarding': (context) => OnboardingScreen(),
        '/home': (context) => HomeScreen(),
        '/assistant': (context) => AssistantScreen(),
      },
    );
  }
}
Related