TabBarView или IndexedStack для BottomNavigationBar - Flutter

Как лучше всего сделать так, чтобы нижняя панель навигации дрожала?

Согласно Основы навигации во Flutter команда флаттера использовала IndexedStack с Offstage, чтобы показать виджет, когда пользователь меняет вкладку, но я вижу, что есть другой способ сделать это, TabBarView для переключения между виджетами с помощью простой анимации слайдов, а также сохранения состояния прокрутки каждого виджета.

Так в чем разница между IndexedStack + Offstage и TabBarView? и как лучше всего изменить текущую вкладку, если я использую что-то вроде flutter_bloc или просто setState()?


person Wail Hayaly    schedule 24.04.2020    source источник


Ответы (1)


OverView

Что ж, есть много способов реализовать BottomNavigationBar во Flutter. Но использование метода IndexedStack создало бы все экраны BottomNavigationBar в начале. Это можно исправить с помощью TabBarView.

Вот как я реализовал BottomNavigationBar в своем приложении, используя CupertinoTabBar и PageView, так как вначале будет только один экран. А также использование AutomaticKeepAliveMixin, так как это не позволит воссоздать экраны снова.


Ключевые точки

  • PageView с PageController, с помощью которого вы можете легко переключаться между экранами.
  • AutomaticKeepAliveClientMixin не позволяет воссоздавать экраны, поэтому нет необходимости использовать IndexedStack.
  • Используйте Provider и Consumer, чтобы воссоздать только CupertinoTabBar при изменении 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;
   }
person DIVYANSHU SAHU    schedule 18.08.2020