Change the size of text dynamically

Hi ! I am developing an app for a pair of glasses that can adjust it’s own zoom (called optical power in the bizz of opticians). We would like to change the size of the font in the app in response to changes in the optical power requested by the wearer in the app. Is there a way to change the scale factor in app for the whole app ? Also, is there a way to propagate this change to the OS ? Preferably in a cross platform way.

I’m not sure about the OS part. do you mean actual user’s device settings i.e. their global preferences for all apps?

You can change the text size across the app by overriding the MediaQuery.

class TextSizeOverride extends StatelessWidget {
  final TextScaler textScaler;
  final Widget child;

  const TextSizeOverride({
    super.key,
    required this.textScaler,
    required this.child,
  });

  @override
  Widget build(BuildContext context) {
    return MediaQuery(
      data: MediaQuery.of(context).copyWith(textScaler: textScaler),
      child: child,
    );
  }
}

Yes, I was talking about the global setting. I think there is no way to do what I want for now. So maybe staying with a global override is the way to go. Where Should I put this code ?

Every widget under: TextSizeOverride will have new text scaler. You can put this at the root of your app. You can wrap the Navigator by providing a builder to MaterialApp / WidgetsApp / CupertinoApp that wraps the child.

Hope this helps:

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

void main() {
  runApp(const App());
}

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

  @override
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  final _scaler = ValueNotifier(TextScaler.noScaling);

  @override
  void initState() {
    super.initState();
    _init();
  }

  @override
  void dispose() {
    _scaler.dispose();
    super.dispose();
  }

  void _init() async {
    // Because scaling affects how the app looks and we need to load it from
    // some internal storage, we can delay rendering so the user doesn't see
    // an improperly scaled UI.
    final binding = RendererBinding.instance..deferFirstFrame();
    final scaler = await _get().whenComplete(binding.allowFirstFrame);

    // Because we performed an async operation, we might have been disposed.
    // Make sure to check if can modify _scaler.
    if (!mounted) return;
    _scaler.value = scaler;
  }

  Future<TextScaler> _get() async {
    // Simulate fetching the saved text scaler from persistent storage
    //
    // For instance: shared_preferences
    await Future.delayed(const Duration(seconds: 1));
    return _options[++_i];
  }

  var _i = 0;
  static const _options = [
    TextScaler.linear(1),
    TextScaler.linear(2),
    TextScaler.linear(3),
    TextScaler.linear(4),
    TextScaler.linear(5),
    TextScaler.linear(10),
  ];

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      builder: _build,
      routes: {
        '/': (_) => Scaffold(
          body: const Center(child: Text('App')),
          floatingActionButton: FloatingActionButton(
            child: const Icon(Icons.dangerous_rounded),
            onPressed: () {
              _scaler.value = _options[_i = ++_i % _options.length];
            },
          ),
        ),
      },
    );
  }

  Widget _build(BuildContext context, Widget? child) {
    // because we used routes, we know the will not be null
    child!;
    return ValueListenableBuilder<TextScaler>(
      valueListenable: _scaler,
      builder: (_, scaler, _) {
        return TextSizeOverride(textScaler: scaler, child: child);
      },
    );
  }
}

class TextSizeOverride extends StatelessWidget {
  final TextScaler textScaler;
  final Widget child;

  const TextSizeOverride({
    super.key,
    required this.textScaler,
    required this.child,
  });

  @override
  Widget build(BuildContext context) {
    return MediaQuery(
      data: MediaQuery.of(context).copyWith(textScaler: textScaler),
      child: child,
    );
  }
}
1 Like

Thanks ! In these times of AI bullshitters, finding a human being availlable for advice is really valuable.

1 Like