【问题标题】:Flutter: Nested routing with persistent BottomNavigationBar but without building the unselected pages unnecessarilyFlutter:具有持久性 BottomNavigationBar 的嵌套路由,但没有不必要地构建未选择的页面
【发布时间】:2021-05-29 22:51:19
【问题描述】:

internetstackoverflow 中,我已经搜索并看到了很多解决嵌套导航问题的方法,这些方法使用 Flutter 应用程序的持久 BottomNavigationBar。其中一些使用 NavigatorsIndexedStackPageView 等等。它们都可以正常工作除了,它们会不必要地构建未选择的选项卡(有时甚至在每次切换选项卡时都重新构建它们),从而使解决方案无法执行。我终于想出了一个解决方案——因为我自己也在努力解决这个问题。

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    该解决方案非常基础,但希望您能够在此基础上进行构建和调整。它实现了以下目标:

    • 在保持 BottomNavigationBar 的同时嵌套导航
    • 除非已被选中,否则不会构建选项卡
    • 保留导航状态
    • 保留滚动状态(例如,ListView

    导入'package:flutter/material.dart';

    void main() {
      runApp(MaterialApp(
        home: MyApp(),
      ));
    }
    
    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      List<Widget> _pages;
    
      List<BottomNavigationBarItem> _items = [
        BottomNavigationBarItem(
          icon: Icon(Icons.home),
          label: "Home",
        ),
        BottomNavigationBarItem(
          icon: Icon(Icons.messenger_rounded),
          label: "Messages",
        ),
        BottomNavigationBarItem(
          icon: Icon(Icons.settings),
          label: "Settings",
        )
      ];
    
      int _selectedPage;
    
      @override
      void initState() {
        super.initState();
        _selectedPage = 0;
    
        _pages = [
          MyPage(
            1,
            "Page 01",
            MyKeys.getKeys().elementAt(0),
          ),
          // This avoid the other pages to be built unnecessarily
          SizedBox(),
          SizedBox(),
        ];
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: WillPopScope(
            onWillPop: () async {
              return !await Navigator.maybePop(
                MyKeys.getKeys()[_selectedPage].currentState.context,
              );
            },
            child: IndexedStack(
              index: _selectedPage,
              children: _pages,
            ),
          ),
          bottomNavigationBar: BottomNavigationBar(
            items: _items,
            currentIndex: _selectedPage,
            onTap: (index) {
              setState(() {
                // now check if the chosen page has already been built
                // if it hasn't, then it still is a SizedBox
                if (_pages[index] is SizedBox) {
                  if (index == 1) {
                    _pages[index] = MyPage(
                      1,
                      "Page 02",
                      MyKeys.getKeys().elementAt(index),
                    );
                  } else {
                    _pages[index] = MyPage(
                      1,
                      "Page 03",
                      MyKeys.getKeys().elementAt(index),
                    );
                  }
                }
    
                _selectedPage = index;
              });
            },
          ),
        );
      }
    }
    
    class MyPage extends StatelessWidget {
      MyPage(this.count, this.text, this.navigatorKey);
      final count;
      final text;
      final navigatorKey;
      @override
      Widget build(BuildContext context) {
        // You'll see that it will only print once
        print("Building $text with count: $count");
        return Navigator(
          key: navigatorKey,
          onGenerateRoute: (RouteSettings settings) {
            return MaterialPageRoute(
              builder: (BuildContext context) {
                return Scaffold(
                  appBar: AppBar(
                    title: Text(this.text),
                  ),
                  body: Center(
                    child: RaisedButton(
                      child: Text(this.count.toString()),
                      onPressed: () {
                        Navigator.of(context).push(MaterialPageRoute(
                            builder: (ctx) => MyCustomPage(count + 1, text)));
                      },
                    ),
                  ),
                );
              },
            );
          },
        );
      }
    }
    
    class MyCustomPage extends StatelessWidget {
      MyCustomPage(this.count, this.text);
      final count;
      final text;
      @override
      Widget build(BuildContext parentContext) {
        return Scaffold(
          appBar: AppBar(
            title: Text(this.text),
          ),
          body: Column(
            children: [
              Expanded(
                child: Container(
                  child: ListView.builder(
                    itemCount: 15,
                    itemBuilder: (context, index) {
                      return Container(
                        width: double.infinity,
                        child: Card(
                          child: Center(
                            child: RaisedButton(
                              child: Text(this.count.toString() + " pos($index)"),
                              onPressed: () {
                                Navigator.of(parentContext).push(MaterialPageRoute(
                                    builder: (ctx) =>
                                        MyCustomPage(count + 1, text)));
                              },
                            ),
                          ),
                        ),
                      );
                    },
                  ),
                ),
              ),
            ],
          ),
        );
      }
    }
    
    class MyKeys {
      static final first = GlobalKey(debugLabel: 'page1');
      static final second = GlobalKey(debugLabel: 'page2');
      static final third = GlobalKey(debugLabel: 'page3');
    
      static List<GlobalKey> getKeys() => [first, second, third];
    }
    

    【讨论】:

    • 感谢您的解决方案。我发现的问题是在 iOS 上点击状态栏时视图不会滚动到顶部。有什么想法吗?
    猜你喜欢
    • 2020-10-11
    • 2021-06-24
    • 1970-01-01
    • 2021-03-04
    • 1970-01-01
    • 2019-08-26
    • 1970-01-01
    • 2014-11-22
    • 1970-01-01
    相关资源
    最近更新 更多