LoginSignup
0
1

More than 1 year has passed since last update.

【Flutter】WebViewの高さをWebページの高さに合わせる

Posted at

 はじめに

使用するパッケージはwebview_flutterです。

SNS埋め込みとかでよく使うWebViewですが、
Columnの中に入れるとA RenderFlex overflowed by Infinity pixels on the bottomでアプリが落ちます。
これ自体はExpandedなどを使えば解決します。

ただ、WebViewの中身をスクロールするのではなく、Flutter側でWidgetをまるっとスクロールさせたい、みたいな場面ってあると思います。
(今回の話は、その為にColumnに入れて使いんたいんじゃい!という話)

固定の高さを持たせて、かつそれをWebページの高さに合わせれば解決なのですが、パッケージ自体にはそんな機能はついておりません。
(Webページの高さを取得できるようにしたwebview_flutter_plusなどもありますが、今回は使いません。

では、どうやって高さを取得するかというと、runJavascriptReturningResultを使用します。

runJavascriptReturningResultとは?

これは、WebViewControllerのメソッドで、WebViewの中でJavascriptを実行する事ができます。
似たようなメソッドにrunJavascriptがありますが、こちらは戻り値がFuture<void>なので今回の用途では使えません。
戻り値がFutureなので、awaitするのを忘れないようにしましょう。

以下サンプルです。

class WebViewTest extends StatefulWidget {
  const WebViewTest({Key? key}) : super(key: key);

  @override 
  State<WebViewTest> createState() => _WebViewTestState();
}

class _WebViewTestState extends State<WebViewTest> {
  late WebViewController _webviewController;
  String _webviewUrl = 'WebViewのURL';
  double _height = 0; // WebViewの高さ

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: <Widget>[
          適当なWidget,
          ...

          SizedBox(
            height: _height, // 高さ指定(ここではまだ0)
            child: WebView(
              initialUrl: _webviewUrl,
              onWebViewCreated: (controller) async {
                _webviewController = controller; // コントローラ取得
              },
              // WebViewが読み込みが完了できたら
              onPageFinished: (_) async {
                double _contentHeight = double.parse(
                  // JSで高さを取得し、doubleにパース
                  await _webviewController
                    .runJavascriptReturningResult('document.documentElement.scrollHeight;'),
                );
                setState(() {
                  _height = _contentHeight; // WebViewの高さを更新
                });
              },
            ),
          ),
        ],
      ),
    );
  }
}

これでWebViewの読み込みが終わり、JSが実行できたら高さがWebページの高さに変わります。

注意点

WebページがJSで画面を構築するページの場合、 onPageFinishedのタイミングで画面構築が終わってない場合があります。
その場合、javascriptChannelsを使ってWebページ側から通知してもらうか、Future.delayedでタイミングをずらしましょう。
(SNSの埋め込みとかだと、通知用のコードを埋め込んでもらうのとかは無理なのでFuture.delayedを使うことになると思います。)

Future.delayedの場合だと、Webページ側の読み込みによって指定する時間が大きく異なると思うので、
ストレスが掛からない程度に大きめに取っておくといいと思います。
(SizedBoxをAnimatedContainerに変えてアニメーションさせたり、AnimatedOpacityでフェードさせたりしてもいいかも)

0
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
0
1