TabBarView 或 IndexedStack 用于 BottomNavigationBar - Flutter

Posted

技术标签:

【中文标题】TabBarView 或 IndexedStack 用于 BottomNavigationBar - Flutter【英文标题】:TabBarView or IndexedStack for BottomNavigationBar - Flutter 【发布时间】:2020-08-08 09:42:56 【问题描述】:

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

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

那么IndexedStack + OffstageTabBarView 之间有什么区别?我应该使用flutter_bloc 还是只使用setState() 来更改当前选项卡的最佳方法是什么?

【问题讨论】:

【参考方案1】:

概览

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

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


关键点

PageViewPageController 可以轻松地在屏幕之间切换。 AutomaticKeepAliveClientMixin 不允许重新创建屏幕,因此无需使用 IndexedStack。 在更改currentIndex 时,使用ProviderConsumer 仅重新创建CupertinoTabBar。而不是使用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更改索引并仅使用Consumer重新创建TabBar

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;
   

【讨论】:

以上是关于TabBarView 或 IndexedStack 用于 BottomNavigationBar - Flutter的主要内容,如果未能解决你的问题,请参考以下文章

带有 IndexedStack 的 AnimatedSwitcher

Flutter中的IndexedStack

Flutter-IndexedStack

Flutter -- 顶部导航栏TabBarView 的基本使用

将固定小部件放在 TabBarView 上方

Flutter:SingleChildScrollView 内的 TabBarView