Flutter showModalBottomSheet with WebView iOS无法滚动

dphi5xsq  于 12个月前  发布在  iOS
关注(0)|答案(1)|浏览(155)

我showModalBottomSheet与Webview显示url https://www.youtube.com它不能滚动时,它显示,必须等待片刻,然后才能滚动,如果我添加任何字符在网页的末尾,它可以随时滚动,或者我没有设置inset,使webview的宽度等于屏幕,它总是可以随时滚动,我尝试使用webview_flutter或flutter_inappwebview,有同样的问题,

设备为iPhone 12 iOS 16.1。

代码

// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// ignore_for_file: public_member_api_docs

import 'package:flutter_inappwebview/flutter_inappwebview.dart';

import 'package:flutter/material.dart';
import 'package:web_test/widget_show_card_rule.dart';
import 'package:webview_flutter/webview_flutter.dart';

void main() => runApp(const MaterialApp(home: WebViewExample()));

class WebViewExample extends StatefulWidget {
  const WebViewExample({super.key});

  @override
  State<WebViewExample> createState() => _WebViewExampleState();
}

class _WebViewExampleState extends State<WebViewExample> {
  late final WebViewController _controller;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.green,
      appBar: AppBar(
        title: const Text('Flutter WebView example'),
      ),
      body: Container(
        height: 300,
        padding: const EdgeInsets.only(left: 15, right: 15),
        child: InAppWebView(
          initialUrlRequest: URLRequest(
              url: Uri.parse(
                  'https://www.youtube.com')),
        ),
      ),
      floatingActionButton: favoriteButton(),
    );
  }

  Widget favoriteButton() {
    return FloatingActionButton(
      onPressed: () async {
        _checkRule();
      },
      child: const Icon(Icons.favorite),
    );
  }

  _checkRule() {
    showModalBottomSheet(
        enableDrag: false,
        isScrollControlled: true,
        context: context,
        backgroundColor: Colors.transparent,
        builder: (context) {
          return const ShowCardRule();
        });
  }
}

个字符

vbopmzt1

vbopmzt11#

我看了一下你的问题,最初滚动不工作的原因是因为你的图像在webview上的加载时间。
即使onPageFinished回调被触发,它也不会加载所有的图像,这就是为什么你可以在web视图中查看大部分文本,但不能查看图像,因此你不能滚动太多。
这个问题实际上并不是来自webview_flutter或inappwebview插件,而是来自网页本身。如果你能在所有图片加载完毕后触发一些动作,你就可以通过从你的网页向flutter webview控制器发送一条消息,让用户知道图片正在加载。
我使用了这篇文章https://stackoverflow.com/a/11071687/14227800的组合;使用一个名为imageLoadCompleter的完成器,以及来自webview的onConsoleMessage回调,以:(0).定义imageLoad完成器。
1.检测加载的所有图像在webview。
1.发送一个控制台消息(更喜欢使用JavaScript通道,我只是不能让它与thoe工作)
1.使用完成器完成
1.使用FutureBuilder和堆栈,在顶部显示webview +加载器,直到图像加载完毕。
下面是使用加载器更新的“ShowCardRule”小部件:

class ShowCardRule extends StatefulWidget {
  const ShowCardRule({super.key});

  @override
  ShowCardRuleState createState() => ShowCardRuleState();
}

class ShowCardRuleState extends State<ShowCardRule> {
  late final WebViewController _controller;
  final Completer imageLoadCompleter = Completer();
  // COMMENT_MATHIS_FOUQUES : Completer that will complete once all images have loaded.

  final Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers = {
    Factory(() => EagerGestureRecognizer())
  };

  final UniqueKey _key = UniqueKey();

  @override
  void initState() {
    super.initState();

    // #docregion platform_features
    late final PlatformWebViewControllerCreationParams params;
    if (WebViewPlatform.instance is WebKitWebViewPlatform) {
      params = WebKitWebViewControllerCreationParams(
        allowsInlineMediaPlayback: true,
        mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},
      );
    } else {
      params = const PlatformWebViewControllerCreationParams();
    }

    final WebViewController controller =
        WebViewController.fromPlatformCreationParams(params);
    // #enddocregion platform_features

    controller
      ..clearCache() // COMMENT_MATHIS_FOUQUES : /!\ TO remove ! Put there for testing purposes.
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..setBackgroundColor(const Color(0x00000000))
      ..setNavigationDelegate(
        NavigationDelegate(
          onProgress: (int progress) {
            debugPrint('WebView is loading (progress : $progress%)');
          },
          onPageStarted: (String url) {
            debugPrint('Page started loading: $url');
          },
          onPageFinished: (String url) {
            _controller.runJavaScript(
              """ var imgs = document.images,
                  len = imgs.length,
                  counter = 0;
                  console.log(imgs);

                  [].forEach.call( imgs, function( img ) {
                      if(img.complete) {
                        incrementCounter();
                      } else {
                        img.addEventListener( 'load', incrementCounter, false );
                      }
                  } );

                  function incrementCounter() {
                      counter++;
                      if ( counter === len ) {
                          console.log( 'LOADED' );
                      }
                  }""",
            );
            // COMMENT_MATHIS_FOUQUES : This will run on pageFinished, on the _controller, that will have been initialised.

            debugPrint('Page finished loading: $url');
          },
          onWebResourceError: (WebResourceError error) {
            debugPrint('''
Page resource error:
  code: ${error.errorCode}
  description: ${error.description}
  errorType: ${error.errorType}
  isForMainFrame: ${error.isForMainFrame}
          ''');
          },
          onNavigationRequest: (NavigationRequest request) {
            if (request.url.startsWith('https://www.youtube.com/')) {
              debugPrint('blocking navigation to ${request.url}');
              return NavigationDecision.prevent;
            }
            debugPrint('allowing navigation to ${request.url}');
            return NavigationDecision.navigate;
          },
          onUrlChange: (UrlChange change) {
            debugPrint('url change to ${change.url}');
          },
        ),
      )
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..addJavaScriptChannel(
        'Toaster',
        onMessageReceived: (JavaScriptMessage message) {
          print(message);
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text(message.message)),
          );
        },
      )
      ..setOnConsoleMessage((message) {
        if (message.message == "LOADED") {
          imageLoadCompleter.complete();
        }

        print(message.message);
      }) // COMMENT_MATHIS_FOUQUES : This console message callback can be replaced by proper use of javascriptChannels, it's just that I couldn't make it work quick enough with js channels.
      ..loadRequest(
        Uri.parse(
            'https://image.fangte.com/TestPro/UploadFiles/H5/RichText/index.html?id=BDB1A583206FED5F975D6D89D9CCB8E1'),
      );

    // #docregion platform_features
    if (controller.platform is AndroidWebViewController) {
      AndroidWebViewController.enableDebugging(true);
      (controller.platform as AndroidWebViewController)
          .setMediaPlaybackRequiresUserGesture(false);
    }
    // #enddocregion platform_features

    _controller = controller;
  }

  @override
  Widget build(BuildContext context) {
    double webHeight = 400;
    double contentTop = 24;
    double titleHeight = 25;
    double topBlankHeight = MediaQuery.of(context).size.height -
        webHeight -
        titleHeight -
        contentTop;

    return Align(
      alignment: Alignment.topCenter,
      child: Column(children: [
        GestureDetector(
          onTap: () {
            Navigator.pop(context);
          },
          child: Container(height: topBlankHeight, color: Colors.transparent),
        ),
        Container(
          decoration: const BoxDecoration(
            borderRadius: BorderRadius.vertical(top: Radius.circular(8)),
            color: Colors.white,
          ),
          padding: EdgeInsets.only(top: contentTop, left: 18, right: 18),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              SizedBox(
                  height: titleHeight,
                  child: Row(
                    children: [
                      Text('使用须知',
                          style: TextStyle(
                              color: HexColor('#333333'),
                              fontSize: 18,
                              fontWeight: FontWeight.w600)),
                      const Expanded(child: SizedBox()),
                      Container(
                        alignment: Alignment.centerRight,
                        width: 60,
                        child: GestureDetector(
                          onTap: () {
                            Navigator.pop(context);
                          },
                        ),
                      )
                    ],
                  )),
              Container(
                height: webHeight,
                padding: const EdgeInsets.only(top: 15),
                child: FutureBuilder(
                    future: imageLoadCompleter
                        .future, // COMMENT_MATHIS_FOUQUES : This will complete when we receive the js message that images have loaded.
                    builder: (context, snapshot) {
                      return Stack(
                        children: [
                          WebViewWidget(
                            key: _key,
                            controller: _controller,
                            gestureRecognizers: gestureRecognizers,
                          ),
                          if (snapshot.connectionState != ConnectionState.done)
                            const Center(
                              child: CircularProgressIndicator
                                  .adaptive(), // COMMENT_MATHIS_FOUQUES : Shows a loader until images are ok, but we can do anything we want.
                              // COMMENT_MATHIS_FOUQUES : The only thing is that the webview still has to be showed, even if images are not loaded.
                            )
                        ],
                      );
                    }),
              )
            ],
          ),
        )
      ]),
    );
  }
}

字符串
我确实把评论与适当的标签来解释这一点。
希望这有帮助

相关问题