底部导航栏的 TabBarView 或 IndexedStack - Flutter

Wai*_*aly 9 flutter flutter-navigation

在颤动中做底部导航栏的最佳方法是什么?

根据获取到导航的颤振底部扑团队使用IndexedStackOffstage显示当用户更改标签的部件,但是我看到有做这个的另一种方式TabBarView,以简单的幻灯片动画控件之间的变化,也保持每个插件的滚动状态

那么IndexedStack+Offstage和之间有什么区别TabBarView?我应该使用类似的东西flutter_bloc还是只使用setState()?

DIV*_*AHU 12

概述

嗯,在 Flutter 中实现的方法有很多种BottomNavigationBar。但使用该IndexedStack方法会在开始时创建所有屏幕BottomNavigationBar。这可以使用 来修复TabBarView

BottomNavigationBar以下是我在应用程序中使用CupertinoTabBarand实现的方法,PageView因为它一开始只会显示一个屏幕。并且使用AutomaticKeepAliveMixin它不会让屏幕再次重新创建。


关键点

  • PageView通过PageController它您可以轻松地在屏幕之间切换。
  • AutomaticKeepAliveClientMixin不允许重新创建屏幕,因此无需使用IndexedStack.
  • 仅在更改 时使用ProviderConsumer重新创建。而不是使用,因为它会重新创建整个屏幕,让所有小部件得到重建。但这里我们仅用于重新创建。CupertinoTabBarcurrentIndexsetState()ProviderTabBar

代码示例

主页 (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 
  ];

}
Run Code Online (Sandbox Code Playgroud)

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

class HomeVM extends ChangeNotifier {
 int _currentPage = 0;

 int get currentPage => _currentPage;

 void changePage(int index) {
   this._currentPage = index;
   notifyListeners();
 }
}
Run Code Online (Sandbox Code Playgroud)

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;
   }
Run Code Online (Sandbox Code Playgroud)