Flutter底部导航栏场景下WebView页面返回按键控制实现问题
修复方案
你遇到的问题核心有两个:
- 两个标签页都属于首页同一个路由下的子组件,只有外层首页的
WillPopScope会响应返回事件,WebView页的WillPopScope根本不会被触发 - 原有WebView的返回逻辑返回值写反,且缺少空安全判断
第一步:修改WebView页(WatchPage)代码
// 注意State类要改为公开(去掉下划线),方便父页面调用 class WatchPage extends StatefulWidget { // 保留你原有构造方法即可 const WatchPage({super.key}); @override State<WatchPage> createState() => WatchPageState(); } class WatchPageState extends State<WatchPage> { WebViewController? controller; // 改为可空类型避免空报错 final Completer<WebViewController> _controller = Completer<WebViewController>(); // 公开的返回事件处理方法,供首页调用 Future<bool> handleBack() async { if (controller != null && await controller!.canGoBack()) { controller!.goBack(); // 返回false表示已经处理返回事件,不需要上层再响应 return false; } // 返回true表示WebView无法回退,需要上层处理 return true; } @override Widget build(BuildContext context) { // 去掉这里的WillPopScope,同路由下不会触发 return Scaffold( appBar: AppBar( toolbarHeight: 10, flexibleSpace: Container( color: const Color(0xff1f5269), ), ), body: Builder(builder: (BuildContext context) { return WebView( initialUrl: widget.text, javascriptMode: JavascriptMode.unrestricted, onWebViewCreated: (WebViewController c) { controller = c; // 直接赋值即可,原有future逻辑冗余 _controller.complete(c); }, onProgress: (int progress) {}, onPageStarted: (String url) { if (url == "https://app.testt.com/Login/Cikis") { Navigator.of(context, rootNavigator: true).push( MaterialPageRoute(builder: (context) => const LoginPage())); } }, onPageFinished: (String url) { if (url == "https://app.testt.com/Login" ) { Navigator.of(context, rootNavigator: true).push( MaterialPageRoute(builder: (context) => const LoginPage())); } }, gestureNavigationEnabled: true, ); }), ); } }
第二步:修改首页代码
// 声明GlobalKey用来获取WebView页的状态 final GlobalKey<WatchPageState> _watchPageKey = GlobalKey<WatchPageState>(); Future<bool> _onBackPressed() async { // 先判断当前是否在WebView标签页 if (_activePage == 1) { bool needParentHandle = await _watchPageKey.currentState?.handleBack() ?? true; if (!needParentHandle) { // WebView已经处理了回退,直接拦截返回事件 return false; } } // 原生页面/ WebView无法回退时,弹出退出确认框 return await (showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Sure?'), content: const Text('???'), actions: <Widget>[ TextButton( onPressed: () => Navigator.of(context).pop(false), child: const Text('No'), ), TextButton( onPressed: () => Navigator.of(context).pop(true), child: const Text('Yes'), ), ], ), )) ?? false; } @override Widget build(BuildContext context) { List<Widget> pageList = [ MainHomePage( text: widget.text, ), // 给WebView页传入GlobalKey WatchPage(key: _watchPageKey) ]; return WillPopScope( onWillPop: _onBackPressed, child: Scaffold( body: Container( child: pageList[_activePage], ), bottomNavigationBar: CurvedNavigationBar( animationCurve: Curves.easeInOut, animationDuration: const Duration(milliseconds: 600), color: const Color(0xff1f5269), backgroundColor: Colors.transparent, onTap: (index) { setState(() { _activePage = index; }); }, items: <Widget>[ const Icon( Icons.home, color: Colors.white, ), const Icon( Icons.tv, color: Colors.white, ), ], ), ), ); }
内容的提问来源于stack exchange,提问作者ozzmhmt
相关产品推荐
相关产品推荐

