BottomNavigatonBar 上的 SetState() 的 onTap(index) 方法不会重建小部件树



我正在尝试将webview_flutter WebView连接到BottomNavigationBar。我希望每当敲击选项卡时,都可以使用新的URL重新加载视图。在onTap回调我将_currentUrl更新为新的URL,并使用新的选项卡索引。

为什么选项卡栏会更新但网络视图未重建?我想念什么?

class WebViewApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return WebViewState();
  }
}
class WebViewState extends State<WebViewApp> {
  int _currentTabIndex = 0;
  String _currentUrl = URL.home;
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter WebView Demo',
      home: Scaffold(
        body: WebView(initialUrl: _currentUrl),
        bottomNavigationBar: BottomNavigationBar(
          currentIndex: _currentTabIndex,
          items: [
            BottomNavigationBarItem(
              icon: Icon(Icons.home),
              title: Text('Home'),
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.search),
              title: Text('Search'),
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.calendar_today),
              title: Text('Profile'),
            ),
          ],
          onTap: (index) {
            switch (index) {
              case 0:
                _currentUrl = URL.home;
                break;
              case 1:
                _currentUrl = URL.search;
                break;
              case 2:
                _currentUrl = URL.calendar;
                break;
            }
            setState(() {
              _currentTabIndex = index;
            });
          },
        ),
      ),
    );
  }
}

您可以使用WebView的WebViewController更改WebView的URL

将以下代码添加到您的WebView小部件:

body: WebView(
  initialUrl: _currentUrl,
  onWebViewCreated: (WebViewController webController) {
    _webController = webController;
  },
),

现在,在将WebViewController提出到WebViewController的实例之后,您可以使用WebViewController的loadUrl((方法更改当前WebView的URL

因此,您可以将ONTAP处理程序的代码更改为以下:

onTap: (index) {
  switch (index) {
    case 0:
      _webController.loadUrl('your_home_url');
    break;
    case 1:
      _webController.loadUrl('your_search_url');
    break;
    case 2:
      _webController.loadUrl('your_calander_url');
    break;
  }
},

WebViews和SetState的问题是整个小部件/页面将重建,包括WebView的实例,但是您只想在当前的WebView会话中更改URL ...

感谢您的评论Joel

是的,发布crossPlatform框架和基本组件确实在一个平台上起作用是非常奇怪的,但是是的,希望他们能在十月的github上对其进行修复……

我检查了我的帖子,WebView应该加载新的URL。我忘记的是在导航的onTap处理程序中更新_currentTabIndex

但是,无论如何:我为您的情况做了一个快速的例子。它对我来说很好...

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {    
    return MaterialApp(
      title: 'WebView App',
      debugShowCheckedModeBanner: false,
      home: WebPage(),
    );
  }
}
class WebPage extends StatefulWidget {
  int currentTabIndex = 0;
  @override
  _WebPageState createState() => _WebPageState();
}
class _WebPageState extends State<WebPage> {
  List<String> _urls = [
    'https://www.zdf.de/nachrichten/heute/rubrik-politik-100.html',
    'https://www.zdf.de/nachrichten/heute/rubrik-wirtschaft-100.html',
    'https://www.zdf.de/nachrichten/heute/rubrik-panorama-100.html'
  ];
  WebViewController _webController;
  @override
  Widget build(BuildContext context) {
    print('<----- build init ----->');
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: Text('WebView'),
      ),
      body: WebView(
        initialUrl: _urls[widget.currentTabIndex],
        javascriptMode: JavascriptMode.unrestricted,
        onWebViewCreated: (WebViewController webController) {
          _webController = webController;
        },
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: widget.currentTabIndex,
        items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.people),
            title: Text('Politik')
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.public),
            title: Text('Wirtschaft')
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.pie_chart_outlined),
            title: Text('Panorama')
          )
        ],
        onTap: (selectedIndex) {
          _webController.loadUrl(_urls[selectedIndex]);         
          setState(() {
            widget.currentTabIndex = selectedIndex;
          });
        },
      ),
    );
  }
}

请注意,我在onTap处理程序的末尾调用setState(),该处理程序重建页面,但却不会初始化WebView!?我认为必须是这种情况,但是Flutter必须在某种程度上或其他方面进行处理...

还要注意,我将您的_currentTabIndex变量从您的WebViewState类移动到其上层父级WebViewApp。问题是,如果您通过setState()重建页面,_currentTabIndex将始终用0重新初始化。为了教程的缘故,我只是向上移动它,但是也许您可以将其用作全局参数...

但是,是的,网络浏览量仍然有些混乱,iOS和Android WebView套件之间有很多差异(归根结底,flutter WebView是"仅"当前本机WebView套件的包装器(

我希望这会有所帮助!

最新更新