(失敗)Flutterで画面外の要素も含めたフルスクリーンショットを撮る方法を調べている話。

以下の記事で「screenshot」パッケージでいけそうと書いていますが、更に調査するとダメでした。画面内の要素(スクリーン高さ)までしか撮れていないことがわかりました。

「来期アニメ」アプリで、自分が今期観ているアニメや来期観る予定のアニメを一覧にしてSNSにシェアする機能を作りたいと思ってます。
テキストでやるとTwitterの140文字制限にかかってしまうので、スクリーンショット画像を共有出来ればよいと考えました。

そこで必要となるのは、スクロール外にあるWidgetまでスクリーンショットの対象とする機能、です。たくさんのアニメを見る人の場合、スクロールが発生する可能性があるからです。

いくつかパッケージを調べて「screenshot」パッケージなら出来るみたいなことをstack overflowで見たので試してみました。

screenshot | Flutter Package
Flutter Screenshot Package (Runtime). Capture any Widget as an image.
dependencies:
  screenshot: ^1.2.3

Widgetツリー内の指定Widgetを撮る方法と、Widgetツリー外のWidgetを撮る方法があるようです。

  • Widgetツリー内のWidgetを撮る方法
# キャプチャを実行する
onPressed: () {
                      screenshotController
                          .capture(delay: Duration(milliseconds: 10))
                          .then((capturedImage) async {
                        ShowCapturedWidget(context, capturedImage!);
                      }).catchError((onError) {
                        print(onError);
                      });
                    },

# キャプチャしたい範囲を囲む
Screenshot(
          controller: screenshotController,
          child: ...

# キャプチャした画像を表示する
  Future<dynamic> ShowCapturedWidget(
      BuildContext context, Uint8List capturedImage) {
    return showDialog(
      useSafeArea: false,
      context: context,
      builder: (context) => Scaffold(
        appBar: AppBar(
          title: Text("Captured widget screenshot"),
        ),
        body: SingleChildScrollView(
          child: Center(
              child: capturedImage != null
                  ? Image.memory(capturedImage)
                  : Container()),
        ),
      ),
    );
  }

結果は以下の通り。

最初にスクリーンショットの対象となる画面。「あいうえ」の下にスクロール(「おかきくけこ」)できます。「フルスクリーンショット」ボタンで、スクリーンショットを撮ります。

撮ったスクリーンショット画像を別画面で表示しました。
「あいうえ」より下にスクロールできません。
つまり、画面の見えている部分しかスクリーンショット撮れていないということです。
これは期待の動作ではありません。

  • Widgetツリー外のWidgetを撮る方法
# キャプチャを実行する
onPressed: () {
                      # キャプチャしたいウィジェット(スクロールあり)を作る
                      var container = SingleChildScrollView(
                        child: Container(
                          padding: const EdgeInsets.all(30.0),
                          decoration: BoxDecoration(
                            border: Border.all(
                                color: Colors.blueAccent, width: 5.0),
                            color: Colors.redAccent,
                          ),
                          child: Column(
                            children: [
                              Text('か', style: TextStyle(fontSize: 50)),
                              Text('き', style: TextStyle(fontSize: 50)),
                              Text('く', style: TextStyle(fontSize: 50)),
                              Text('け', style: TextStyle(fontSize: 100)),
                              Text('こ', style: TextStyle(fontSize: 100)),
                              Text('さ', style: TextStyle(fontSize: 100)),
                              Text('し', style: TextStyle(fontSize: 100)),
                              Text('す', style: TextStyle(fontSize: 100)),
                              Text('せ', style: TextStyle(fontSize: 100)),
                              Text('そ', style: TextStyle(fontSize: 100)),
                            ],
                          ),
                        ),
                      );
                     # キャプチャを実行する
                      screenshotController
                          .captureFromWidget(
                              InheritedTheme.captureAll(
                                  context, Material(child: container)),
                              delay: Duration(seconds: 1))
                          .then((capturedImage) {
                        ShowCapturedWidget(context, capturedImage);
                      });
                    },
                  ),

  # キャプチャした画像を表示する(↑と同じ)
  Future<dynamic> ShowCapturedWidget(
      BuildContext context, Uint8List capturedImage) {
    return showDialog(
      useSafeArea: false,
      context: context,
      builder: (context) => Scaffold(
        appBar: AppBar(
          title: Text("Captured widget screenshot"),
        ),
        body: SingleChildScrollView(
          child: Center(
              child: capturedImage != null
                  ? Image.memory(capturedImage)
                  : Container()),
        ),
      ),
    );
  }

結果は以下の通り。

最初にスクリーンショット対象画面。Widgetツリー外のため、画面には見えていませんが「かきくけこさしすせそ」(スクロールあり)を仕込んでいます。
「ウィジェットツリー外のウィジェットをとる」ボタンで、スクリーンショットを撮ります。

撮ったスクリーンショットを別画面で表示しました。
「かきくけ」より下にスクロールして、「さし」まで表示できます。
つまり、画面の見えてない部分のスクリーンショットが撮れている期待の動作です!

しかし、スクロールは出来ますが、「さし」までしか出ません(「すせそ」までスクロールできないう)。この原因は調べる必要があります。もしかしたら画像の縦サイズの最大値が決まっている?

↓スクロール

今日のところは、スクロール外の部分までスクリーンショットを撮れる可能性がわかったところまでとします。「さし」までしか出ない問題は明日以降に調査する予定です。

個人開発で自作アプリ作ってます。是非インストールお願いします。

コメント

  1. […] Flutterで画面外の要素も含めたフルスクリーンショットを撮る方法を調べて… […]

タイトルとURLをコピーしました