androidflutterdartwidget

Retain the font size of the app even if the device's font size changes in Flutter


This is a pending issue in my current Flutter project. The case scenario is that I tried to intercept the process of Flutter in rendering the UI with the font to maintain the scale of the text as 1.

This is the code I used in main.dart:

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(
    MediaQuery(
      data: MediaQueryData.fromView(
              WidgetsBinding.instance.platformDispatcher.views.single)
          .copyWith(
              textScaler: const TextScaler.linear(
                  1)), //intercept font size changes from user's device
      child: const TestFontScale(),
    ),
  );
}

In my TestFontScale class:

class TestFontScale extends StatefulWidget {
  const TestFontScale({super.key});

  @override
  State<TestFontScale> createState() => _TestFontScaleState();
}

class _TestFontScaleState extends State<TestFontScale> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            const Text(
              "Hello World",
              textDirection: TextDirection.ltr,
            ),
            Container(
              padding: const EdgeInsets.only(top: 8.0),
              child: TextFormField(
                decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                  hintText: 'Put some text',
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

First, I resize the font size from the device settings:

settings

After the changes in the font size of the device:

overlapping_keyboard

Then I Photoshopped the screenshot images (i.e., simple opacity adjustments to make the background of the keyboard visible there) to show what happened:

unexpected

NOTE: I want to prevent this from happening.

But if I use a default where I don't intercept the text scale:

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(
    const TestFontScale(),
    // MediaQuery(
    //   data: MediaQueryData.fromView(
    //           WidgetsBinding.instance.platformDispatcher.views.single)
    //       .copyWith(
    //           textScaler: const TextScaler.linear(
    //               1)), //intercept font size changes from user's device
    //   child: const TestFontScale(),
    // ),
  );
}

Here's the expected behavior of the app (except the font size XD):

expected_ux

I observed that the

MediaQuery(
      data: MediaQueryData.fromView(
              WidgetsBinding.instance.platformDispatcher.views.single)
          .copyWith(
              textScaler: const TextScaler.linear(
                  1)), //intercept font size changes from user's device
      child: const MyApp(),
    ),

intercept how the other widget should behave, such as how the TextFormField is being affected when I set the code above in main.dart.

I want to maintain the font size of the app even if there are changes in the device settings without affecting other widgets, such as when the TextFormField is receiving focus and then the keyboard appears after this instance.

Does anybody know how I can achieve a text scale with 1 without affecting other widget behavior?

Any help would be appreciated and entertained.


Solution

  • the purpose of mediaquery's font scaler is to scale the values according to the system's preferences. So for your case, it scales the text wherever its present.

    However if you don’t want to have scaling in some parts of your app you can have a wrapper which overrides the system set preferences of scaling

    that wrapper can be as simple as

    class NoScaleWrappingWidget extends StatelessWidget {
      final Widget child;
      const NoScaleWrappingWidget({super.key, required this.child});
    
      @override
      Widget build(BuildContext context) {
        return MediaQuery(
            data: MediaQueryData.fromView(
                    WidgetsBinding.instance.platformDispatcher.views.single)
                .copyWith(textScaler: const TextScaler.linear(1)),
            child: child);
      }
    }