【问题标题】:Bottom navigation bar is reloading all the widgets each time I press a navigation item每次按下导航项时,底部导航栏都会重新加载所有小部件
【发布时间】:2018-11-25 18:59:50
【问题描述】:

以下代码几乎是从底部导航栏的官方 Flutter GitHub 示例中复制粘贴的。问题是,在打开包含视图的小部件时,所有内容都已预加载。每次按下底部栏元素时,我都会重新加载所有视图。换句话说,当我按下第一个项目时,日志显示其他项目(第二个和第三个)正在拨打网络电话。当我按第二个时,日志显示我什至第一个正在拨打网络电话。当我调试时,我发现每次我从底部栏中选择一个小部件时,包含它的小部件都会重建(有一个对方法 build 的调用)。这是正常行为吗?这是包含小部件的代码

class MainScreen extends StatefulWidget{
    
    @override
      State<StatefulWidget> createState()=> MainScreenState();
    
}


class MainScreenState extends State<MainScreen> with TickerProviderStateMixin{
      GlobalKey<ScaffoldState> scaffoldState = new GlobalKey();
      int _currentSelection = 0;
      BottomNavigationBarType _navigationBarType = BottomNavigationBarType.fixed;
      Li

    st<NavigationIconView> _navigationIcons;


    @override
      void initState() {
       

    super.initState();
        _navigationIcons = <NavigationIconView>[
          new NavigationIconView(
        

    icon: const Icon(Icons.home),
        title: 'Главная',
        vsync: this

      ),
      new NavigationIconView(
        icon: const Icon(Icons.map),
        title: 'Квесты',
        vsync: this
      ),
      new NavigationIconView(
        icon: const Icon(Icons.dehaze),
        title: 'Профиль',
        vsync: this
      )
    ];

    for(NavigationIconView v in _navigationIcons)
      v.controller.addListener(_rebuild);

    _navigationIcons[_currentSelection].controller.value = 1.0;
      }


    @override
      void dispose() {
        for(NavigationIconView v in _navigationIcons)
          v.controller.dispose();
        super.dispose();
    }

     @override
      Widget build(BuildContext context) {
        final BottomNavigationBar botNavBar = new BottomNavigationBar(
          items: _navigationIcons
              .map((NavigationIconView navigationView) => navigationView.item)
              .toList(),
          currentIndex: _currentSelection,
          fixedColor: Colors.green,
          type: _navigationBarType,
          onTap: (int index) {
            setState(() {
              _navigationIcons[_currentSelection].controller.reverse();
              _currentSelection = index;
              _navigationIcons[_currentSelection].controller.forward();
              print('pressed : $_currentSelection');
            });
          },
        );
        return new Scaffold(
          key: scaffoldState,
          body: new  Center(
            key: new Key('Main view container'),
            child: new FutureBuilder<Widget>(
                future: _buildTransitionsStack(),
                builder: (BuildContext context, AsyncSnapshot<Widget> snapshot){
                  if(!snapshot.hasError) return snapshot.data;
                  else{
                    print('sh3t happened in main : ${snapshot.error}');
                  }
                }
            ),
          ),
      bottomNavigationBar: botNavBar,

    );
  }


    Future<Widget> _buildTransitionsStack() {
        final List<FadeTransition> transitions = <FadeTransition>[];
    
        return _showMain().then((mainWidget){
          transitions.add(_navigationIcons[0]
           

    .transition(_navigationBarType,mainWidget, context));
          print('size ${transitions.length}');
        }).then((_){
          transitions.add(_navigationIcons[1].transition(_navigationBarType,
              _showQuest(), context));
    
          transitions.add(_navigationIcons[2].transition(_navigationBarType,
              _showProfile(), context));
    
          transitions.sort((FadeTransition a, FadeTransition b) {
          final Animation<double> aAnimation = a.opacity;
          final Animation<double> bAnimation = b.opacity;
          final double aValue = aAnimation.value;
          final double bValue = bAnimation.value;
          return aValue.compareTo(bValue);
        });
    
          return new Stack(children: transitions);
        });
        }

  Future<Widget> _showMain(){
     return _getToken().then((token){
      return new FeedView(token);
    });
  }

  Widget _showQuest(){
//    return DetailableListScreen(ViewModelType.QUEST);

    return new QuestScreen();

  }

  Widget _showProfile(){
    return new Text('profile');
//    TODO
  }


  void _rebuild() {
    setState(() {

    });
  }

  Future<String> _getToken() async{
    return await SharedPreferences.getInstance()
        .then((SharedPreferences sp)=> sp.getString(TOKEN)
    );
  }
}}

【问题讨论】:

    标签: flutter dart bottomnavigationview


    【解决方案1】:

    在切换选项卡时保持页面活动的解决方案是将页面包装在 IndexedStack 中。

    class Tabbar extends StatefulWidget {
      Tabbar({this.screens});
    
      static const Tag = "Tabbar";
      final List<Widget> screens;
      @override
      State<StatefulWidget> createState() {
      return _TabbarState();
      }
    }
    
    class _TabbarState extends State<Tabbar> {
      int _currentIndex = 0;
      Widget currentScreen;
    
      @override
      Widget build(BuildContext context) {
        var _l10n = PackedLocalizations.of(context);
    
        return Scaffold(
      body: IndexedStack(
        index: _currentIndex,
        children: widget.screens,
      ),
      bottomNavigationBar: BottomNavigationBar(
        fixedColor: Colors.black,
        type: BottomNavigationBarType.fixed,
        onTap: onTabTapped,
        currentIndex: _currentIndex,
        items: [
          BottomNavigationBarItem(
            icon: new Icon(Icons.format_list_bulleted),
            title: new Text(_l10n.tripsTitle),
          ),
          BottomNavigationBarItem(
            icon: new Icon(Icons.settings),
            title: new Text(_l10n.settingsTitle),
          )
        ],
      ),
    );
      }
    
      void onTabTapped(int index) {
        setState(() {
          _currentIndex = index;
        });
      }
    }
    

    【讨论】:

    • 我试过了,IndexedStack 使应用程序非常慢,甚至小部件也无法正常工作。
    • 我遇到了同样的问题,'IndexedStack' 非常慢
    • IndexedStack 预加载所有小部件,但我希望小部件在我们第一次选择任何菜单项时加载一次。
    【解决方案2】:

    我强烈推荐观看 @amrnt 视频。但是对于那些想要直接答案的人,您需要为底部栏部分的每个页面实例化一个PageStorageKey,然后让每个页面通过构造函数接收其 PageStorageKey。

    【讨论】:

      【解决方案3】:

      更好的方法是使用 IndexedStack 而不是 PageStorage 或 AutomaticKeepAliveClientMixin。

      class _MainActivityState extends State<MainActivity> {
      
        int _selectedPage = 0;
        List<Widget> pageList = List<Widget>();
      
        @override
        void initState() {
          pageList.add(HomePage());
          pageList.add(ChatPage());
          super.initState();
        }
      
       @override
        Widget build(BuildContext context) {
          return Scaffold(
            appBar: AppBar(
              title: Text(widget.title),
            ),
            body: IndexedStack(
              index: _selectedPage,
              children: pageList,
            ),
            //Bottom Navigation Bar added
            bottomNavigationBar: BottomNavigationBar(
          .....
      

      IndexedStack Widget 是 Stack Widget 的子类 它显示提供的孩子列表中的单个孩子。它的大小和最大的孩子一样大。它保持所有孩子的状态。

      【讨论】:

        猜你喜欢
        • 2020-06-16
        • 2020-02-07
        • 1970-01-01
        • 2018-05-10
        • 1970-01-01
        • 1970-01-01
        • 2022-08-13
        • 1970-01-01
        • 2020-02-11
        相关资源
        最近更新 更多