Flutter WebView实现下拉刷新时RefreshIndicator失效如何解决
Flutter WebView 下拉刷新不生效解决方案
RefreshIndicator默认仅响应可滚动组件的下拉手势,WebView本身的滚动事件默认无法被RefreshIndicator捕获,因此直接嵌套不会触发刷新效果。
实现步骤
- 新增滚动位置监听变量,记录WebView当前是否滚动到页面顶部
- 新增JS通道接收网页滚动位置回调
- 页面加载完成后注入JS监听网页滚动事件
- 调整页面结构,嵌套RefreshIndicator和SingleChildScrollView保证下拉手势可被识别
修改后的完整代码
// 新增变量记录网页是否滚动到顶部 bool _isWebAtTop = true; // 新增滚动事件JS通道 JavascriptChannel _scrollListenerChannel(BuildContext context) { return JavascriptChannel( name: 'ScrollListener', onMessageReceived: (JavascriptMessage message) { _isWebAtTop = message.message == "true"; }, ); } @override Widget build(BuildContext context) { return Scaffold( appBar: PreferredSize( preferredSize: MediaQuery.of(context).size * 0.05, child: AppBar( //leading: Image.asset(gnTabIcon), elevation: 3.5, shadowColor: AppColors.navyBlue, backgroundColor: AppColors.orange, title: const Text(title), actions: <Widget>[ NavigationControls(_controller.future), // control navigation ], ), ), // build scaffold for main app body: Builder( builder: (BuildContext context) { return RefreshIndicator( onRefresh: () async { // 仅网页滚动到顶部时触发刷新 if(_isWebAtTop) { final controller = await _controller.future; controller.reload(); } }, child: SingleChildScrollView( // 强制可滚动,保证内容不足一屏时也能触发下拉 physics: const AlwaysScrollableScrollPhysics(), child: SizedBox( // 高度设置为可用屏幕高度,撑满空间 height: MediaQuery.of(context).size.height - (MediaQuery.of(context).size.height * 0.05) -15, child: Stack( children: [ Padding( padding: const EdgeInsets.fromLTRB(0, 0, 0, 15.0), child: WebView( gestureNavigationEnabled: false, initialUrl: url, javascriptMode: JavascriptMode.unrestricted, zoomEnabled: false, // disable pinch to zoom // 增加垂直手势识别,避免滚动冲突 gestureRecognizers: { Factory<VerticalDragGestureRecognizer>(() => VerticalDragGestureRecognizer()), }, onWebViewCreated: (webViewController) { print('WebView is created'); _controller.complete(webViewController); }, onProgress: (int progress) { print("WebView is loading (progress : $progress%)"); splashScreenDelay(progress); }, javascriptChannels: <JavascriptChannel>{ _toasterJavascriptChannel(context), // 注册滚动监听通道 _scrollListenerChannel(context), }, onPageStarted: (String url) { print('Page started loading: $url'); _loadingStateTrue(); }, onPageFinished: (String url) async { print('Page finished loading: $url'); _loadingStateFalse(); // 页面加载完成后注入JS监听滚动位置 final controller = await _controller.future; controller.runJavascript(''' window.addEventListener("scroll", function() { ScrollListener.postMessage(window.pageYOffset == 0 ? "true" : "false"); }); '''); }, ), ), isLoading ? Center( child: GnLoader(), ) : const SizedBox.shrink(), ], ), ), ), ); }, ), ); }
注意事项
- 可根据实际布局调整SizedBox的高度计算逻辑,保证WebView撑满可用空间
- 如果网页本身存在嵌套滚动容器,可调整JS监听逻辑,适配对应容器的scrollTop属性即可
- 原有WebView的业务逻辑无需修改,不会影响原有功能
内容的提问来源于stack exchange,提问作者Gurjit Singh
相关产品推荐
相关产品推荐

