颤动中的底部导航栏不会在点击选项卡时切换屏幕

Posted

技术标签:

【中文标题】颤动中的底部导航栏不会在点击选项卡时切换屏幕【英文标题】:Bottom Navigation Bar in flutter not switching screens on tapping on the tabs 【发布时间】:2020-07-30 03:37:24 【问题描述】:

参考Hans Muller's article在Flutter中创建淡入淡出效果并使用底部导航栏,以下代码在点击时不会切换屏幕。即使在我点击不同的底部导航栏项目后,它也会保持在同一屏幕上,即主屏幕上。

以下是我的代码的 sn-p,主要是文章中代码的副本。当我点击导航栏按钮时,我似乎无法理解为什么屏幕转换不起作用。

class NavigationRouterScreen extends StatefulWidget 
  @override
  _NavigationRouterScreenState createState() => _NavigationRouterScreenState();


class _NavigationRouterScreenState extends State<NavigationRouterScreen> with TickerProviderStateMixin<NavigationRouterScreen> 
  List<Key> _destinationKeys;
  List<AnimationController> _faders;
  AnimationController _hide;
  int _currentIndex = 0;

  @override
  void initState() 
    super.initState();
    _faders = allDestinations.map<AnimationController>((Destination destination) 
      return AnimationController(vsync: this, duration: Duration(milliseconds: 200));
    ).toList();
    _faders[_currentIndex].value = 1.0;
    _destinationKeys = List<Key>.generate(allDestinations.length, (int index) => GlobalKey()).toList();
    _hide = AnimationController(vsync: this, duration: kThemeAnimationDuration);
  

  @override
  void dispose() 
    for (AnimationController controller in _faders)
      controller.dispose();
    _hide.dispose();
    super.dispose();
  

  bool _handleScrollNotification(ScrollNotification notification) 
    if (notification.depth == 0) 
      if (notification is UserScrollNotification) 
        final UserScrollNotification userScroll = notification;
        switch (userScroll.direction) 
          case ScrollDirection.forward:
            _hide.forward();
            break;
          case ScrollDirection.reverse:
            _hide.reverse();
            break;
          case ScrollDirection.idle:
            break;
        
      
    
    return false;
  

  Color colorByIndex(int index) 
    return index == _currentIndex ? Color(0xFF323255) : Colors.grey;
  

  List<Widget> allChildren() 
    var listofitems = allDestinations.map((Destination destination) 
      final Widget view = FadeTransition(
        opacity: _faders[destination.index].drive(CurveTween(curve: Curves.fastOutSlowIn)),
        child: KeyedSubtree(
          key: _destinationKeys[destination.index],
          child: DestinationView(
            destination: destination,
            onNavigation: () 
              _hide.forward();
            ,
          ),
        ),
      );
      if (destination.index == _currentIndex) 
        _faders[destination.index].forward();
        return view;
       else 
        _faders[destination.index].reverse();
        if (_faders[destination.index].isAnimating) 
          return IgnorePointer(child: view);
        
        return Offstage(child: view);
      
    ).toList();
    return listofitems;
  

  @override
  Widget build(BuildContext context) 
    return NotificationListener(
      onNotification: _handleScrollNotification,
      child: Scaffold(
        bottomNavigationBar: ClipRect(
          child: SizeTransition(
            sizeFactor: _hide,
            axisAlignment: -1.0,
            child: BottomNavigationBar(
              type: BottomNavigationBarType.fixed,
              currentIndex: _currentIndex,
              onTap: (int index) 
                setState(() 
                  _currentIndex = index;
                );
              ,
              items: allDestinations.map((Destination destination) 
                return BottomNavigationBarItem(
                  icon: SvgPicture.asset(
                    destination.iconPath,
                    height: 24.0,
                    width: 24.0,
                    color: colorByIndex(destination.index),
                  ),
                  title: Text(destination.title,
                    style: TextStyle(
                      fontSize: 11.0,
                      color: colorByIndex(destination.index),
                    ),
                  ),
                );
              ).toList(),
            ),
          ),
        ),
        body: SafeArea(
          top: false,
          child: Stack(
            fit: StackFit.expand,
            children: allChildren(),
          ),
        ),
      ),
    );
  

class DestinationView extends StatefulWidget 
  const DestinationView( Key key, this.destination, this.onNavigation ) : super(key: key);

  final Destination destination;
  final VoidCallback onNavigation;

  @override
  _DestinationViewState createState() => _DestinationViewState();


class _DestinationViewState extends State<DestinationView> 

  Route _registerRoutesWithParameters(RouteSettings settings) 
    return MaterialPageRoute(
      settings: settings,
      builder: (context) 
        switch(settings.name) 
          case RouteConstants.home:
            print(settings.name);
            return HomeScreen(destination: widget.destination);
          case RouteConstants.stats:
            return StatsScreen(destination: widget.destination);
          case RouteConstants.profile:
            return ProfileScreen(destination: widget.destination);
          default:
            return HomeScreen(destination: widget.destination);
        
      ,
    );
  

  @override
  Widget build(BuildContext context) 
    return Navigator(
      observers: <NavigatorObserver>[
        ViewNavigatorObserver(widget.onNavigation),
      ],
      onGenerateRoute: _registerRoutesWithParameters,
    );
  


class ViewNavigatorObserver extends NavigatorObserver 
  ViewNavigatorObserver(this.onNavigation);

  final VoidCallback onNavigation;

  void didPop(Route<dynamic> route, Route<dynamic> previousRoute) 
    onNavigation();
  
  void didPush(Route<dynamic> route, Route<dynamic> previousRoute) 
    onNavigation();
  

【问题讨论】:

【参考方案1】:

尝试如下替换您的代码:

    switch (widget.destination.index) 
          case 0:
            switch (settings.name) 
               case RouteConstants.home:
                 return HomeRootPage(destination: widget.destination);
               case RouteConstants.home_list:
                 return HomeListPage(destination: widget.destination);
               case RouteConstants.home_text:
                 return HomeTextPage(destination: widget.destination);
            
            break;
          case 1:
            switch (settings.name) 
               case RouteConstants.stats:
                 return StatsRootPage(destination: widget.destination);
               case RouteConstants.stats_list:
                 return StatsListPage(destination: widget.destination);
               case RouteConstants.stats_text:
                 return StatsTextPage(destination: widget.destination);
            
            break;

【讨论】:

以上是关于颤动中的底部导航栏不会在点击选项卡时切换屏幕的主要内容,如果未能解决你的问题,请参考以下文章

如何在颤动的底部导航栏中添加抽屉?

Flutter:带有嵌套导航的底部导航栏和更改选项卡时恢复根页面

颤动底部导航,其中一个页面有选项卡

使用底部导航栏颤动保存 PageView 内每个页面的状态

移动到其他页面时无法保持底部导航栏颤动

颤动中的不同导航栏