Flutter InAppWebView搭配IndexedStack时控制器仅对最后一个页面生效
问题原因
你只定义了单个InAppWebViewController?类型的变量存储控制器,而IndexedStack初始化时会一次性构建所有子节点,3个WebView会按顺序触发onWebViewCreated回调,每触发一次就会覆盖一次webViewController变量的值,最终变量里存的永远是最后一个加载完成的WebView实例的控制器,所以所有控制器操作只会作用在最后一个页面上。
修复方法
不需要替换IndexedStack,只需要把单控制器存储改成按索引一一对应的控制器集合,操作时始终取当前选中页面对应的控制器即可,完全保留页面不重载、状态不丢失的特性。
具体修改点:
- 删除原来的单控制器变量,新增和网页列表长度一致的控制器数组
- 每个WebView触发
onWebViewCreated时,按循环索引把控制器存入数组对应位置 - 所有调用控制器逻辑的位置(比如返回键拦截、JS调用、网页控制等),都通过当前选中的索引
_currentIndex取对应位置的控制器操作 - 给每个WebView添加唯一的
ValueKey,避免组件重建时状态混乱
修复后可直接运行的核心代码
class _ShowItemsState extends State<ShowItems> { List services = [ { 'service_name': 'expample1', 'website_link': 'https://www.example1.com/', 'icon': const Icon(Icons.location), 'color': const Color(0xffE23744) }, { 'service_name': 'expample2', 'website_link': 'https://www.expample2.com/', 'icon': const Icon(Icons.location_on), 'color': const Color(0xfff18423) }, { 'service_name': 'expample3', 'website_link': 'https://www.expample3.com/', 'icon': const Icon(Icons.location), 'color': const Color(0xff801A00) }, ]; // 按索引存储每个网页对应的控制器 final List<InAppWebViewController?> _webControllers = List.filled(3, null); int _currentIndex = 0; @override Widget build(BuildContext context) { return WillPopScope( onWillPop: () async { // 仅操作当前显示页面对应的控制器 final currentController = _webControllers[_currentIndex]; if (await currentController?.canGoBack() == true) { currentController?.goBack(); return false; } return true; }, child: LayoutBuilder( builder: (context, constraints) { final cmh = constraints.maxHeight; return Scaffold( appBar: AppBar( backgroundColor: services[_currentIndex]['color'], elevation: 0, title: Text(services[_currentIndex]['service_name']), actions: [ IconButton( onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => const SettingsScreen(), )); }, icon: const Icon(Icons.settings), splashRadius: cmh * 0.021, ) ], ), body: IndexedStack( index: _currentIndex, children: [ for (int x = 0; x < services.length; x++) InAppWebView( key: ValueKey('webview_$x'), initialUrlRequest: URLRequest( url: Uri.parse(services[x]['website_link'])), onWebViewCreated: (controller) { _webControllers[x] = controller; }, initialOptions: InAppWebViewGroupOptions( android: AndroidInAppWebViewOptions( allowContentAccess: true, builtInZoomControls: true, thirdPartyCookiesEnabled: true, allowFileAccess: true, geolocationEnabled: true, supportMultipleWindows: true, ), crossPlatform: InAppWebViewOptions( useShouldOverrideUrlLoading: true, useOnDownloadStart: true, allowFileAccessFromFileURLs: true, allowUniversalAccessFromFileURLs: true, ), ), ), ], ), bottomNavigationBar: BottomNavigationBar( type: BottomNavigationBarType.fixed, selectedIconTheme: IconThemeData( color: services[_currentIndex]['color'] ?? Colors.amber), selectedItemColor: services[_currentIndex]['color'] ?? Colors.amber, currentIndex: _currentIndex, items: [ for (int i = 0; i < services.length; i++) BottomNavigationBarItem( label: services[i]['service_name'], icon: services[i]['icon'], ), ], onTap: (int index) { setState(() { _currentIndex = index; }); }, ), ); }, ), ); } }
原代码中多余的
PageController是为PageView组件设计的,和IndexedStack无关,可以直接删除避免无用代码干扰。
内容的提问来源于stack exchange,提问作者Spicier Ewe
相关产品推荐
相关产品推荐

