🎼

Flutterで端末の文字サイズ設定を無視する方法

2022/07/10に公開
2

iPhoneやAndroidの端末の設定には、文字サイズを好みの大きさに変更する機能があります。標準アプリなど、端末設定にしっかり準拠しているアプリは、設定によって見た目が大きく変わります。

Flutterの開発を始めて驚いたのは Text(str, style: TextStyle(fontSize: 24)) といった形でいわゆる「文字サイズ」を指定したつもりになっていても、端末の設定によって文字の大きさが変化することでした。これまでずっと開発をしてきたiOSだと、UIFontTextStyleHeadline のような抽象的なスタイルで指定した時に端末設定に従うため、Flutterも同様の仕様だと勝手に勘違いをしていました。

端末の設定では、かなり衝撃的なバカでかいサイズも設定できるので、アプリのUIによってはこの辺の動作をしっかり調整する必要があると感じて調べました。

開発環境での文字サイズ設定

まず、シミュレータやエミュレータで文字サイズを変更する方法を書いておきます。

iOSは、設定アプリから設定します。「アクセシビリティ → 画面表示とテキストサイズ → さらに大きな文字」と進んで変更します。相当大きなサイズも選べます。

iOS標準 iOS最大(標準の3.1倍)

Androidは、エミュレータによって違うかもしれませんが、同じく設定の「ディスプレイ → フォントサイズ」から変更できます。スクリーンショットはPixel_5_API_31です。

Android標準 Android最大(標準の1.3倍)

文字サイズの拡縮範囲

iOS、Androidともに標準設定の場合に等倍で表示されます。

Androidは0.85〜1.3倍の範囲で拡大縮小します。

iOSは「さらに大きな文字」を使わなければ、約0.8〜1.35倍の範囲で、「さらに大きな文字」をオンにすると、最大約3.1倍まで拡大できます。

個別のTextウィジェットで端末設定を無視する

さて本題です。まずは特定のTextウィジェットのみ、フォントサイズを固定して表示してみます。textScaler プロパティを使います。以下のようにすると、style で指定したサイズに固定されます。端末設定の等倍表示と等価ということですね。

Text(str,
   style: TextStyle(fontSize: 24),
   textScaler: TextScaler.noScaling,
);

特定のウィジェット配下のTextウィジェットで端末設定を無視する

MediaQuery を使うと、特定の子要素すべてにおいて textScaler を強制できます。たとえば、以下のようにしてページ全体をchild配下に入れてしまえば、その中にあるTextウィジェットはすべてここで指定した textScaler の値になります。

MediaQuery(
  data: MediaQuery.of(context).copyWith(textScaler: TextScaler.linear(1.5)),
  child: ここ,
);

アプリケーション全体で端末設定を無視する

文字サイズはもう自分たちで決めたものだけで固定にしたい、という場合も多いでしょう。全体に適用する場合はRoot要素にあるであろう MaterialApp 内で MediaQuery を使ってしまうと良いです。

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MediaQuery.withNoTextScaling(
        child: const HomePage(),
      ),
    );
  }
}

特定の範囲内なら文字サイズの変更も許可したい

これまでの方法だと、完全に指定したサイズでしか表示されないので、ユーザー目線で考えるとあまり好ましくありません。できればある程度大きい文字や小さい文字でも表示できるように対応したいものです。

あまりにも大きいサイズは諦めるとしても、指定した範囲内でのサイズ調整も可能です。以下の例では、0.9倍〜1.2倍まで許容します。最小、最大サイズの片方だけを指定しても反映されます。

return MaterialApp(
  home: MediaQuery.withClampedTextScaling(
    minScaleFactor: 0.9,
    maxScaleFactor: 1.2,
    child: const HomePage(),
  ),
);
GitHubで編集を提案

Discussion

kira_sogakira_soga

記事とてもわかりやすかったです。
細かいところですが、、、
https://zenn.dev/ktakayama/articles/1b741f765b4f24#アプリケーション全体で端末設定を無視する
こちらの

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

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

に修正いただけるととても嬉しいです。