🔤

TextScaleFactorの個人的まとめ😇

2023/10/11に公開

概要

Android/iOSの本体設定から文字サイズまたは表示サイズを変更した場合、アプリ内のText要素などにも影響が及んだ。(今回私のケースでは折り返しを想定していない要素やプルダウンのレイアウトがこぞって表記崩れ、またはエラーを起こした🫠)

iOS16.2ではテキストサイズが最大310%、Android13までは最大130%、Android14以降は最大200%に設定ができるようになる、ということも踏まえ、そんなに大きな文字でアプリ使うか...?と思いつつ今後はアプリも高齢化社会に対応すべきと捉えてTextScaleFactorを調整する対応を施した、というのが概要。

そもそもTextScaleFactorって?

ざっくり、Flutterは基本的には端末の文字サイズによってTextの大きさが変わるようになっていて、「端末の文字サイズを変更することでアプリ側の文字サイズも変更できる機能(文字サイズにかかる倍率)」がTextScaleFactorの正体と考えている。
(間違っていたらすみませぬ🙇‍♂️)

対応内容

背景として、
・今回はAndroidに限定してエラーが発生していた。
・OSごとに調整するのは手間がかかりすぎる。
・すでにリリースされており、早めに対応したい。
・ユーザーの年齢層は高め。

体験的に文字サイズの設定を無効化することはユーザビリティに欠ける&後々サイズが変わるようにしてくれと要望がありそうだったため、TextScaleFactorの最小値・最大値を決めて調整した。

参考記事はこちら↓↓↓
https://developers.cyberagent.co.jp/blog/archives/36310/

dart
/// TextScaleFactorの最大値を調整するWidget
class TextScaleFactor extends StatelessWidget {
  const TextScaleFactor({
    super.key,
    required this.child,
  });

  static const _maxTextScaleFactor = 1.5;
  static const _midLTextScaleFactor = 1.3;
  static const _midSTextScaleFactor = 1.2;
  static const _minTextScaleFactor = 1.1;
  static const _minDeviceSizeWidth = 320.0;
  static const _midDeviceSizeWidth = 350.0;
  static const _maxDeviceSizeWidth = 485.0;

  final Widget child;

  @override
  Widget build(BuildContext context) {
    final mediaQuery = MediaQuery.of(context);

    // TextScaleFactorの最大値
    // 485px以上:1.5
    // 350以上 ~ 485px未満:1.3
    // 320以上 ~ 350px未満:1.2
    // 320px未満:1.1
    final screenWidthSize = MediaQuery.of(context).size.width;
    double upperTextScaleFactor;

    if (screenWidthSize >= _maxDeviceSizeWidth) {
      upperTextScaleFactor = _maxTextScaleFactor;
    } else if (screenWidthSize >= _midDeviceSizeWidth) {
      upperTextScaleFactor = _midLTextScaleFactor;
    } else if (screenWidthSize >= _minDeviceSizeWidth) {
      upperTextScaleFactor = _midSTextScaleFactor;
    } else {
      upperTextScaleFactor = _minTextScaleFactor;
    }

    final textScaleFactor =
        mediaQuery.textScaleFactor.clamp(1.0, upperTextScaleFactor);

    return MediaQuery(
      data: mediaQuery.copyWith(
        textScaleFactor: textScaleFactor,
      ),
      child: child,
    );
  }
}

調査

PIXEL6を元に文字サイズ・表示サイズ変更時の画面サイズを調査

文字サイズ

文字サイズ

文字サイズ設定 _dx _dy aspectRatio
7 411.42857142857144 914.2857142857143 0.45
6 411.42857142857144 914.2857142857143 0.45
5 411.42857142857144 914.2857142857143 0.45
4 411.42857142857144 914.2857142857143 0.45
3 411.42857142857144 914.2857142857143 0.45
2 411.42857142857144 914.2857142857143 0.45
1 411.42857142857144 914.2857142857143 0.45
表示サイズ

表示サイズ

表示サイズ設定 _dx _dy aspectRatio
5 320.0 711.1111111111111 0.45
4 345.6 768.0 0.45
3 375.6521739130435 834.7826086956521 0.45000000000000007
2 411.42857142857144 914.2857142857143 0.45
1 485.3932272197492 1078.651616043887 0.45

結論

表示サイズ設定が5の時と1の時では見えている範囲がギュッと狭くなっていることがわかる。
要するに、ギュッとなったときに文字サイズも大きくなってしまうとより大きく表示される(ように見える)ため、表示サイズに合わせてtextScaleFactorの最大値を決めようよ、というのが今回の趣旨。

文字サイズはほとんどの場合FlexibleWrapなどで調整すれば問題ない。(TextScaleFactorを可変にしたことでデザインが崩れるのが嫌なら固定にすれば良い)

表示サイズの方は機種にもよるが画面の横幅に影響されることが大きく、めっちゃ画面の小さいAndroidで表示サイズを変えられるとやはり厳しい部分はある。
固定にはさせたくないけど、対応に迷う部分はtextScaleFactor: min(1.35, textScaleFactor),など個別に対応を入れて調整を図る必要はある。

「アプリの機能性を失わない」を考えると、実装でなんとかできる部分も少なくはないが、Figmaなどのデザイン時にモバイルアプリとしてのデザインを見失わない or 要件として何倍までは表示できるようにする などを決めておいても良いかもしれない。

CyberAgentのWINTICKETアプリのtextScaleFactorの闘いがかなり参考になりました🙇‍♂️
ありがとうございました。

Discussion