颤抖:bottomNavigationBar无法使用WebView

时间:2020-09-08 06:51:39

标签: html flutter dart

目标

我使用bottomNavigationBar在几页之间切换。其中两个页面使用WebView来显示本地html文件。

问题

我发现,当我在这些页面之间切换时,带有纯颤动小部件的页面可以完美加载。但是HTML页面只会在切换时显示最初加载的页面。

例如,如果我有两个指向Page1和Page2的导航器按钮,则在运行时,如果我先轻按Page1按钮,然后轻按Page2按钮,则WebView仍将显示Page1而不是Page2。这是错误的。

代码

这是我使用的HTML页面代码

class LocalLoader {
  Future<String> loadLocal(String filename) async {
    return await rootBundle.loadString('assets/doc/$filename');
  }
}
class HtmlPage extends StatelessWidget {
  final String htmlFile;
  HtmlPage({
    @required this.htmlFile
  });
  @override
  Widget build(BuildContext context) {
    return Container(
      child: FutureBuilder<String>(
        future: LocalLoader().loadLocal(htmlFile),
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return WebView(
              initialUrl: Uri.dataFromString(snapshot.data,
                  mimeType: 'text/html',
                  // CAUTION
                  // - required for non-ascii chars
                  encoding: Encoding.getByName("UTF-8")
              ).toString(),
              javascriptMode: JavascriptMode.unrestricted,
            );
          } else if (snapshot.hasError) {
            return Text("${snapshot.error}");
          } else {
            print('undefined behaviour');
          }
          return CircularProgressIndicator();
        },
      ),);
  }
}

然后用我的bottomNavigationBar处理点击事件:

class MyFlutterView extends StatefulWidget {
  @override
  _MyFlutterViewState createState() => _MyFlutterViewState();
}
class _MyFlutterViewState extends State<MyFlutterView> {
  final Keys keys = Keys();
  int _iSelectedDrawerItem = 3; // self
  int _iSelectedNavItem = 0;
  static List<Widget> _widgetOptions = <Widget>[
    MyFlutterPlaceholder(title: 'Index 0: MyFlutter'),
    MyPage(htmlFile: 'page1.html'),
    MyPage(htmlFile: 'page2.html'),
  ];

  void _onItemTapped(int index) {
    setState(() {
      _iSelectedNavItem = index;
    });
  }
  @override
  Widget build(BuildContext context) {
    final deviceSize = MediaQuery.of(context).size;
    final appBar = AppBar(
      backgroundColor: WidgetColors.menubar,
      title: Text('MyFlutter'),
    );
    return Scaffold(
      appBar: appBar,
      endDrawer: NavDrawer(
        keys: keys,
        iSelectedDrawerItem: _iSelectedDrawerItem,
      ),
      body: Container(
        decoration: BoxDecoration(
            gradient: WidgetColors.canvas,
        ),
        child: _widgetOptions.elementAt(_iSelectedNavItem),
      ),
      bottomNavigationBar: BottomNavigationBar(
          currentIndex : _iSelectedNavItem,
          type: BottomNavigationBarType.fixed,
          backgroundColor: WidgetColors.menubar,
          fixedColor: WidgetColors.myColor,
          // selectedItemColor: WidgetColors.myColor,
          unselectedItemColor: Colors.white,
          selectedIconTheme: IconThemeData(color: WidgetColors.myColor),
          // unselectedIconTheme: IconThemeData(color: Colors.white),
          items: [
            BottomNavigationBarItem(
              label: 'MyFlutter',
              icon: Icon(Icons.build)
            ),
            BottomNavigationBarItem(
              label: 'Page1-HTML',
              icon: Icon(Icons.help,),
            ),
            BottomNavigationBarItem(
              label: 'Page2-HTML',
              icon: Icon(Icons.info_outline_rounded),
            ),
          ],
          onTap: _onItemTapped),
    );
  }
}

我也尝试过StatefulWidgets,但问题仍然存在。

解决方法

我目前唯一的解决方法是从HtmlPage类派生我拥有的每个页面,就像这样:

class Page1 extends HtmlPage {
  Page1() : super(htmlFile: 'page1.html');
}

class Page2 extends HtmlPage {
  Page2() : super(htmlFile: 'page2.html');
}

此后,HTML页面将按预期切换并加载。

问题

该如何解决?我应该更明确地加载HTML文件吗?我以为setState会自动为我处理加载,这当然适用于纯flutter小部件页面(上面代码中的MyFlutterPlaceholder类)。

此外,我确保每次通过导航栏切换页面时都调用URL加载。

1 个答案:

答案 0 :(得分:1)

您可以在下面复制粘贴运行完整代码
我用下面的完整代码模拟这种情况
步骤1:使用AutomaticKeepAliveClientMixin

class _WebViewKeepAlive extends State<WebViewKeepAlive>
    with AutomaticKeepAliveClientMixin {
    
    @override
  bool get wantKeepAlive => true;
  
  @override
  Widget build(BuildContext context) {
    super.build(context);

步骤2:请勿在{{1​​}}属性future中直接放置函数,请按以下方式使用

future: LocalLoader().loadLocal(htmlFile),

第3步:在这种情况下,我使用Future<String> _future; @override void initState() { _future = _getUrl(widget.url); super.initState(); } return FutureBuilder( future: _future,

工作演示

enter image description here

完整代码

PageView