💩

Flutter Web (CanvasKit) で日本語や絵文字の描画問題を回避する

2021/05/05に公開

問題

CanvasKitでの描画はhtmlに比べてパフォーマンスが高く、環境による描画の差がない利点があリますが、2バイト文字や絵文字が一時的にいわゆる "Tofu" になってしまうことがissueとして上げられています。

https://github.com/flutter/flutter/issues/53897
https://github.com/flutter/flutter/issues/60037

(例)

↓ 数秒後...

現在、Flutter WebはCanvasKitがデフォルトのレンダラーです(デスクトップ向けの場合)。--web-renderer でhtmlを指定するかモバイルで閲覧すればこの問題は回避できるのですが、デスクトップでCanvasKitレンダラーを使う場合でも回避できる方法を紹介します。

回避方法

Tofuになってしまう文字が含まれるフォントをプロジェクトに組み込んで、MaterialAppの {theme: } などでフォント指定するだけです。

(例)pubspec.yaml

  fonts:
    - family: Hiragino Maru
      fonts:
        - asset: fonts/Hiragino_Maru.ttc
    - family: Color Emoji
      fonts:
        - asset: fonts/Apple Color Emoji.ttc

(例)日本語フォントを全体のテーマに指定

MaterialApp(
      theme: ThemeData(
        fontFamily: 'Hiragino Maru', // ←
        primaryColor: Colors.cyan,
        accentColor: Colors.yellow,
        elevatedButtonTheme: ElevatedButtonThemeData(
          style: ElevatedButton.styleFrom(
            primary: Colors.cyan[700],
            onPrimary: Colors.white,
          ),
        ),
      ),
    );

(例)絵文字フォントを個別指定(Apple Color Emoji 使用)

Text(
        'あいうえお💩',
        style: TextStyle(
          fontFamilyFallback: ['Color Emoji'], // ←
        ),
      ),

結果

描画直後にきちんと表示されることがわかるように Future.delayed() でTextの読み込みを遅らせています。


CanvasKitでの日本語と絵文字の描画

{style: } プロパティがあるWidgetであれば、Text Widget だけでなく TextField Widget などにも応用が可能です。

Discussion