How to preserve widget states in flutter, when navigating using BottomNavigationBar?

后端 未结 6 1392
青春惊慌失措
青春惊慌失措 2020-11-27 12:20

I\'m currently working on building a Flutter app that will preserve states when navigating from one screen, to another, and back again when utilizing BottomNavigationBar. Ju

相关标签:
6条回答
  • 2020-11-27 12:49

    For keeping state in BottomNavigationBar, you can use IndexedStack

        @override
          Widget build(BuildContext context) {
            return Scaffold(
              bottomNavigationBar: BottomNavigationBar(
                onTap: (index) {
                  setState(() {
                    current_tab = index;
                  });
                },
                currentIndex: current_tab,
                items: [
                  BottomNavigationBarItem(
                    ...
                  ),
                  BottomNavigationBarItem(
                    ...
                  ),
                ],
              ),
              body: IndexedStack(
                children: <Widget>[
                  PageOne(),
                  PageTwo(),
                ],
                index: current_tab,
              ),
            );
          }
    
    0 讨论(0)
  • 2020-11-27 13:01

    Use AutomaticKeepAliveClientMixin to force your tab content to not be disposed.

    class PersistantTab extends StatefulWidget {
      @override
      _PersistantTabState createState() => _PersistantTabState();
    }
    
    class _PersistantTabState extends State<PersistantTab> with AutomaticKeepAliveClientMixin {
      @override
      Widget build(BuildContext context) {
        return Container();
      }
    
      // Setting to true will force the tab to never be disposed. This could be dangerous.
      @override
      bool get wantKeepAlive => true;
    }
    

    To make sure your tab does get disposed when it doesn't require to be persisted, make wantKeepAlive return a class variable. You must call updateKeepAlive() to update the keep alive status.

    Example with dynamic keep alive:

    // class PersistantTab extends StatefulWidget ...
    
    class _PersistantTabState extends State<PersistantTab>
        with AutomaticKeepAliveClientMixin {
      bool keepAlive = false;
    
      @override
      void initState() {
        doAsyncStuff();
      }
    
      Future doAsyncStuff() async {
        keepAlive = true;
        updateKeepAlive();
        // Keeping alive...
    
        await Future.delayed(Duration(seconds: 10));
    
        keepAlive = false;
        updateKeepAlive();
        // Can be disposed whenever now.
      }
    
      @override
      bool get wantKeepAlive => keepAlive;
    
      @override
      Widget build(BuildContext context) {
        super.build();
        return Container();
      }
    }
    
    0 讨论(0)
  • 2020-11-27 13:07

    The most convenient way I have found to do so is using PageStorage widget along with PageStorageBucket, which acts as a key value persistent layer.

    Go through this article for a beautiful explanation -> https://steemit.com/utopian-io/@tensor/persisting-user-interface-state-and-building-bottom-navigation-bars-in-dart-s-flutter-framework

    0 讨论(0)
  • 2020-11-27 13:09

    Late to the party, but I've got a simple solution. Use the PageView widget with the AutomaticKeepAliveClinetMixin.

    The beauty of it that it doesn't load any tab until you click on it.


    The page that includes the BottomNavigationBar:

    var _selectedPageIndex;
    List<Widget> _pages;
    PageController _pageController;
    
    @override
    void initState() {
      super.initState();
    
      _selectedPageIndex = 0;
      _pages = [
        //The individual tabs.
      ];
    
      _pageController = PageController(initialPage: _selectedPageIndex);
    }
    
    @override
    void dispose() {
      _pageController.dispose();
    
      super.dispose();
    }
    
    @override
    Widget build(BuildContext context) {
      ...
        body: PageView(
          controller: _pageController,
          physics: NeverScrollableScrollPhysics(),
          children: _pages,
        ),
       bottomNavigationBar: BottomNavigationBar(
          ...
          currentIndex: _selectedPageIndex,
          onTap: (selectedPageIndex) {
            setState(() {
              _selectedPageIndex = selectedPageIndex;
              _pageController.jumpToPage(selectedPageIndex);
            });
          },
      ...
    }
    

    The individual tab:

    class _HomeState extends State<Home> with AutomaticKeepAliveClientMixin<Home> {
      @override
      bool get wantKeepAlive => true;
    
      @override
      Widget build(BuildContext context) {
        //Notice the super-call here.
        super.build(context);
        ...
      }
    }
    

    I've made a video about it here.

    0 讨论(0)
  • 2020-11-27 13:10

    Use “IndexedStack Widget” with “Bottom Navigation Bar Widget” to keep state of Screens/pages/Widget

    Provide list of Widget to IndexedStack and index of widget you want to show because IndexedStack show single widget from list at one time.

    final List<Widget> _children = [
        FirstClass(),
        SecondClass()
      ];
    
    Scaffold(
      body: IndexedStack(
        index: _selectedPage,
        children: _children,
      ),
      bottomNavigationBar: BottomNavigationBar(
        ........
        ........
      ), 
    );
    
    0 讨论(0)
  • 2020-11-27 13:12

    Instead of returning new instance every time you run pageChooser, have one instance created and return the same.

    Example:

    class Pages extends StatefulWidget {
      @override
      createState() => new PagesState();
    }
    
    class PagesState extends State<Pages> {
      int pageIndex = 0;
    
      // Create all the pages once and return same instance when required
      final ProfilePage _profilePage = new ProfilePage(); 
      final PlanPage _planPage = new PlanPage();
      final StartUpNamerPage _startUpNamerPage = new StartUpNamerPage();
    
    
      Widget pageChooser() {
        switch (this.pageIndex) {
          case 0:
            return _profilePage;
            break;
    
          case 1:
            return _planPage;
            break;
    
          case 2:
            return _startUpNamerPage;
            break;
    
          default:
            return new Container(
              child: new Center(
                  child: new Text(
                      'No page found by page chooser.',
                      style: new TextStyle(fontSize: 30.0)
                  )
              ),
            );
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
            home: new Scaffold(
                body: pageChooser(),
                bottomNavigationBar: new BottomNavigationBar(
                  currentIndex: pageIndex,
                  onTap: (int tappedIndex) { //Toggle pageChooser and rebuild state with the index that was tapped in bottom navbar
                    setState(
                            (){ this.pageIndex = tappedIndex; }
                    );
                  },
                  items: <BottomNavigationBarItem>[
                    new BottomNavigationBarItem(
                        title: new Text('Profile'),
                        icon: new Icon(Icons.account_box)
                    ),
                    new BottomNavigationBarItem(
                        title: new Text('Plan'),
                        icon: new Icon(Icons.calendar_today)
                    ),
                    new BottomNavigationBarItem(
                        title: new Text('Startup'),
                        icon: new Icon(Icons.alarm_on)
                    )
                  ],
                )
            )
        );
      }
    }
    

    Or you can make use of widgets like PageView or Stack to achieve the same.

    Hope that helps!

    0 讨论(0)
提交回复
热议问题