1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

FlutterのPlatform Viewsの表示モードを整理する

Posted at

はじめに

FlutterはiOSやAndroidなど複数のプラットフォームで動作するUIフレームワークです。Flutterは独自のUIレンダリングの仕組みを持っており、基本的には各プラットフォームのネイティブUIを使用しないため、プラットフォーム間での動作の差異がほとんどないという特徴があります。

しかしながらマップやウェブビューなど、プラットフォームが提供しているUIをFlutterで表示したいことがあります。そのようなケースに対応するための仕組みが Platform Views です。

あるプラットフォーム上でそのプラットフォーム向けのUIを表示する(例えばiOSでUIButtonを表示する)というのは当たり前なことです。しかし、それをFlutterで構築されたアプリの中で表示する場合、Flutterが独自にレンダリングするUIとプラットフォームのUIを同時に組み合わせて表示しなければならないことになります。

iOS/Androidにおけるそのような課題をFlutterはどのように解決しているのか?を整理する機会があったため、こちらの記事にまとめます。

記事中に各表示モードにおいてネイティブでのビュー階層がどうなっているかを、以下のようなプラットフォームビューを含むWidgetで示します。

  • 背面に緑色のWidget
  • 中間にプラットフォームビューとしてGoogle MapsのWidget
  • 前面に青色のWidget
iOS Android
  @override
  Widget build(BuildContext context) {
    final size = MediaQuery.of(context).size;
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Platform Views'),
        ),
        body: Stack(
          alignment: Alignment.center,
          children: [
            SizedBox(
              width: size.width,
              height: size.height,
              child: const ColoredBox(color: Colors.green),
            ),
            SizedBox(
              width: size.width,
              height: size.height * 0.4,
              child: const GoogleMap(
                initialCameraPosition: CameraPosition(
                  target: LatLng(37.42796133580664, -122.085749655962),
                  zoom: 15,
                ),
              ),
            ),
            SizedBox(
              width: size.width * 0.2,
              height: size.height,
              child: const ColoredBox(color: Colors.blue),
            ),
          ],
        ),
      ),
    );
  }

Android

AndroidにおけるPlatform Viewsの表示モードは以下の3種類から選択することができます。なぜ3つも選択肢があるのかというと、それぞれの表示モードに異なるメリット・デメリットがあり、利用シーンによって最適なモードが異なるためです。逆に言うと、現時点で万能な表示モードが存在しないということになります。

  • Virtual Display
  • Hybrid Composition
  • Texture Layer Hybrid Composition

Virtual Display

  • プラットフォームビューをAndroidのVirtual Displayに描画し、その内容をFlutterのTextureに接続する方式
  • テキスト入力やアクセシビリティなどの機能において互換性の問題が発生する
    • プラットフォームビューがVirtuarl Display内で描画され、実際にはAndroidのビュー階層に存在しないことが原因と思われる
  • Android SDK 20(4.4W / KitKat Watch)以降で利用可能
  • 公式Wiki / Virtual Display

Hybrid Composition

  • Androidのビュー階層の中に直接プラットフォームビューを表示する方式
    • プラットフォームビューの背面にあるFlutter UIを表示する層
    • プラットフォームビューを表示する層
    • プラットフォームビューの前面にあるFlutter UIを表示する層
  • プラットフォームビューがAndroidのビュー階層の中にいるため、Virtual Displayのような互換性の問題が発生しにくい
  • パフォーマンス面で問題があり、特にAndroid 10.0(Q)以前のバージョンが顕著
  • Android SDK 19(4.4 / KitKat)以降で利用可能
  • 公式Wiki / Hybrid Composition

Hybrid Compositionのビュー階層

プラットフォームビューの前面にくるFlutterのWidgetは、複数のビューに分割されて描画されているのが興味深いです。

FlutterImageView

Android_ビュー階層_HC3.png

ImageReader によって提供された Flutter UI を Canvas に描画します。
FlutterImageView は、開発者が Flutter UI をレンダリングする必要があるが、同時に対話型のPlatformView もレンダリングする必要がある状況を想定しています。
このビューは、Flutter UI を画像として提供する ImageReader を取得し、onDraw でそれを Canvas にレンダリングします。

(リファレンスからの抜粋をChatGPTにて翻訳)

FlutterMutatorView / FlutterMutatorsStack

Android_ビュー階層_HC4.png

ミューテータは PlatformView に適用され、一連の変換を行うことができます。Mutators に関する情報については、FlutterMutatorsStack.FlutterMutator を参照してください。

(リファレンスからの抜粋をChatGPTにて翻訳)

PlatformOverlayView

Android_ビュー階層_HC5.png

Flutter コンテンツをプラットフォームビュー上に表示するためのホストビュー。

(リファレンスからの抜粋をChatGPTにて翻訳)

Texture Layer Hybrid Composition

  • Virtual Display・Hybrid Compositionそれぞれの問題を解決して置き換えることを目的に開発され、Flutter 3にて導入された新しい方式
  • Hybrid Compositionのようにプラットフォームビューは実際に画面上の正しい位置に配置される
  • Virtual Displayと同様に描画はTextureを使用し、drawをリダイレクトすることでTextureに描画内容を反映する
  • プラットフォームビューが SurfaceView そのもの、もしくはそれを含む場合に機能しない
    • これによりVirtual DisplayやHybrid Compositionを完全に置き換えられない
  • Android SDK 23(6.0 / Marshmallow)以降で利用可能
  • 公式Wiki / Texture Layer Hybrid Composition

Texture Layer Hybrid Compositionのビュー階層

FlutterSurfaceView

Android_ビュー階層_TLHC2.png

PlatformViewWrapper

Android_ビュー階層_TLHC3.png

プラットフォームビューをラップしてジェスチャーをインターセプトし、このビューをPlatformViewRenderTarget に投影します。
Android プラットフォームビューは、TextureLayer を使用してエンジンによって構成されます。ビューは通常のビューのように Android ビューヒエラルキーに埋め込まれますが、PlatformViewRenderTarget に投影されるため、エンジンによって効率的に構成できます。
ビューは Android ビューヒエラルキーに存在するため、キーボードおよびアクセシビリティの操作は通常通りに動作します。

(リファレンスからの抜粋をChatGPTにて翻訳)

表示モードの指定方法

Flutterの PlatformViewService の初期化方法によって表示モードを指定することができる。

※ 以下のいずれかの場合は Texture Layer Hybrid Compositionモードを適用できない

  • Android SDK 23未満
  • プラットフォームビューに SurfaceView を含む

iOS

iOSの表示モードはHybrid Compositionのみです。AndroidのHybrid Compositionと同じ仕組みをとっていますが、パフォーマンス面の問題もないようです。

公式Wiki / Hybrid Composition iOS

ビュー階層

FlutterView

iOS_ビュー階層_HC1.png

ChildClippingView > FlutterTouchInterceptingView

iOS_ビュー階層_HC2.png

FlutterOverlayView

iOS_ビュー階層_HC3.png

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?