用于BottomNavigationBar的TabBarView或IndexedStack-Flutter

时间:2020-04-24 18:10:33

标签: flutter flutter-navigation

在颤振中制作底部导航栏的最佳方法是什么?

根据Getting to the Bottom of Navigation in Flutter,当用户更改标签时,flutter团队使用IndexedStackOffstage来显示小部件,但是我看到{{1}还有另一种方法}可以通过简单的幻灯片动画在小部件之间进行切换,并保持每个小部件的滚动状态

那么TabBarView + IndexedStackOffstage有什么区别?更改当前选项卡的最佳方法是使用TabBarView之类的东西还是仅使用flutter_bloc

1 个答案:

答案 0 :(得分:1)

概述

嗯,有许多方法可以在Flutter中实现BottomNavigationBar。 但是,使用IndexedStack方法将在一开始创建BottomNavigationBar的所有屏幕。可以使用TabBarView来解决。

这是我使用BottomNavigationBarCupertinoTabBar在我的应用中实现PageView的方式,因为它一开始只会显示一个屏幕。并且还使用AutomaticKeepAliveMixin,因为它不会让屏幕重新创建。


关键点

  • PageViewPageController,可轻松在屏幕之间切换。
  • AutomaticKeepAliveClientMixin不允许重新创建屏幕,因此无需使用IndexedStack
  • 更改Provider时,使用ConsumerCupertinoTabBar仅重新创建currentIndex。而不是使用setState(),因为它将重新创建整个屏幕,让所有小部件都可以重新构建。但是这里使用Provider仅重新创建TabBar

代码示例

主页(BottomNavigtionBar

class HomeScreen extends StatefulWidget {
  @override
 _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
PageController _pageController;

@override
void initState() {
  _pageController = PageController();
  super.initState();
}

@override
void dispose() {
  _pageController.dispose();
  super.dispose();
}

@override
Widget build(BuildContext context) {
return  Scaffold(
    // Wrapping the CupertinoTabBar in Consumer so that It only get 
    // recreated.
    bottomNavigationBar: Consumer<HomeVM>(
      builder: (context, model, child) {
        return CupertinoTabBar(
            backgroundColor: Colors.white10,
            currentIndex:  model.currentPage,
            onTap: (index) {
                index == model.currentPage
                ? print('same screen')
                : _pageController.jumpToPage(
                    index,
                  );
                 model.changePage(index);
                }, 
            items: bottomNavItems);
      },
    ),
    body:ChangeNotifierProvider(
           create: (_) => locator<HelpVM>(),
           child: SafeArea(
                    top: false,
                    child: PageView(
                    controller: _pageController,
                    physics: NeverScrollableScrollPhysics(),
                    children: <Widget>[
                          FrontScreen(),
                          WorkRootScreen(),
                          HelpScreen(),
                          AccountScreen(),
                     ],
                   ),
          ),
       ),
  );
 }

  const List<BottomNavigationBarItem> bottomNavItems = 
   <BottomNavigationBarItem>[
     BottomNavigationBarItem(
       icon: const Icon(
       FontAwesomeIcons.home,
     ),
   ),
    //...... bottomNavigationBarItems 
  ];

}

HomeVM(使用Provider更改索引并使用TabBar仅重新创建Consumer

class HomeVM extends ChangeNotifier {
 int _currentPage = 0;

 int get currentPage => _currentPage;

 void changePage(int index) {
   this._currentPage = index;
   notifyListeners();
 }
}

FrontScreen(这里我们使用AutomaticKeepAliveClientMixin通过不重新创建窗口小部件来保留状态)

   class FrontScreen extends StatefulWidget {
    @override
      _FrontScreenState createState() => _FrontScreenState();
    }
    
    class _FrontScreenState extends State<FrontScreen>
        with AutomaticKeepAliveClientMixin {
      @override
      Widget build(BuildContext context) {
      // VIMP to Add this Line.
        super.build(context);
        return SafeArea(
         // Your Screen Code   
        );
      }
    
      @override
      bool get wantKeepAlive => true;
   }