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

2024-06-20

我是 Flutter 开发的新手。我已经阅读了多个教程来了解底部导航栏。

我已经尝试过这些教程,但无法达到我的要求。 我遵循的教程:

  1. https://codewithandrea.com/articles/multiple-navigators-bottom-navigation-bar/ https://codewithandrea.com/articles/multiple-navigators-bottom-navigation-bar/
  2. https://medium.com/flutter/getting-to-the-bottom-of-navigation-in-flutter-b3e440b9386 https://medium.com/flutter/getting-to-the-bottom-of-navigation-in-flutter-b3e440b9386
  3. https://medium.com/@theboringdeveloper/common-bottom-navigation-bar-flutter-e3693305d2d https://medium.com/@theboringdeveloper/common-bottom-navigation-bar-flutter-e3693305d2d

我个人喜欢第一个教程,因为有嵌套路由。

信息:

我的底部导航有 3 个选项卡:主页、日历、个人资料。

Home选项卡有一个屏幕:Screen2. Calendar有一个屏幕:Screen3. Profile有一个屏幕:Screen4

Problem:

我的底部导航栏保留了屏幕的状态(这很好)。

主屏幕有一个打开的按钮Screen2。当用户单击时,它会推动 Screen2。当用户单击日历(选项卡)时,用户会看到日历屏幕。现在,用户再次单击“主页”按钮(选项卡),用户将看到 Screen2。因为它是那条路线(家)的一部分。他应该只看到主屏幕。

我只想重置它。基本上主屏幕应该推送主屏幕并弹出主页的所有子项。当选项卡切换时。

Code:

主程序.dart

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MainScreen(),
    );
  }
}

主屏幕.dart

class MainScreen extends StatefulWidget {
  MainScreen({Key key}) : super(key: key);

  @override
  _MainScreenState createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  int _selectedIndex = 0;

  List<GlobalKey<NavigatorState>> _navigatorKeys = [
    GlobalKey<NavigatorState>(),
    GlobalKey<NavigatorState>(),
    GlobalKey<NavigatorState>()
  ];

  List<Widget> _widgetOptions = <Widget>[
    HomePage(),
    CalendarPage(),
    ProfilePage(),
  ];

  Map<String, WidgetBuilder> _routeBuilders(BuildContext context, int index) {
    return {
      '/': (context) {
        return [
          HomePage(),
          CalendarPage(),
          ProfilePage(),
        ].elementAt(index);
      },
    };
  }


  Widget _buildOffstageNavigator(int index) {
    var routeBuilders = _routeBuilders(context, index);

    return Offstage(
      offstage: _selectedIndex != index,
      child: Navigator(
        key: _navigatorKeys[index],
        onGenerateRoute: (routeSettings) {
          return MaterialPageRoute(
            builder: (context) => routeBuilders[routeSettings.name](context),
          ); 
        },
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        final isFirstRouteInCurrentTab =
        !await _navigatorKeys[_selectedIndex].currentState.maybePop();

        // let system handle back button if we're on the first route
        return isFirstRouteInCurrentTab;
      },
      child: Scaffold(
        backgroundColor: Colors.white,
        body: SafeArea(
          child: Stack(
            children: [
              _buildOffstageNavigator(0),
              _buildOffstageNavigator(1),
              _buildOffstageNavigator(2),
            ],
          ),
        ),
        bottomNavigationBar: BottomNavigationBar(
          currentIndex: _selectedIndex,
          showSelectedLabels: false,
          showUnselectedLabels: false,
          items: [
            BottomNavigationBarItem(
              icon: Icon(
                Feather.home,
                color: Colors.grey[300],
              ),
              label: 'HOME',
              activeIcon: Icon(
                Feather.home,
                color: Colors.purple[300],
              ),
            ),
            BottomNavigationBarItem(
              icon: Icon(
                FontAwesome.calendar,
                color: Colors.grey[300],
              ),
              label: 'CALENDAR',
              activeIcon: Icon(
                FontAwesome.calendar,
                color: Colors.purple[300],
              ),
            ),
            BottomNavigationBarItem(
              icon: Icon(
                EvilIcons.user,
                color: Colors.grey[300],
                size: 36,
              ),
              label: 'PROFILE',
              activeIcon: Icon(
                EvilIcons.user,
                color: Colors.purple[300],
                size: 36,
              ),
            ),
          ],
          onTap: (index) {
            setState(() {
              _selectedIndex = index;
            });
          },
        ),
      ),
    );
  }
}

主页.dart

class HomePage extends StatefulWidget {
  HomePage();

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Container(
        color: Colors.lightBlueAccent,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            Container(
              child: Text(
                'Screen 1',
                style: TextStyle(color: Colors.white, fontSize: 20),
              ),
              margin: EdgeInsets.all(16),
            ),
            FlatButton(
              onPressed: () {
                // Navigator.push(context, MaterialPageRoute(
                //   builder: (context) => Screen2()
                // ));

                Navigator.push(context, PageRouteBuilder(pageBuilder: (_,__,___) => Screen2()));
              },
              child: Text('Go to next screen'),
              color: Colors.white,
            ),
          ],
        ));
  }
}

日历页.dart

class CalendarPage extends StatefulWidget {
  CalendarPage({Key key}) : super(key: key);

  @override
  _CalendarPageState createState() => _CalendarPageState();
}

class _CalendarPageState extends State<CalendarPage> {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      child: Center(
        child: FlatButton(
          onPressed: (){
            Navigator.push(context, MaterialPageRoute(
                builder: (context) => Screen3()
            ));
          },
          child: Text('Go to next screen'),
          color: Colors.white,
        ),
      ),
    );
  }
}

如果有人能给我指出方向,我将非常感激。提前致谢。

要求: 有选项卡,每个选项卡都有各自的屏幕(ScreenX-> ScreenY-> ScreenN)。当切换选项卡时,它应该弹出选项卡的所有子选项卡。我希望这是可以理解的(抱歉,我的英语不好)。

我在这里缺少什么?


所以逻辑是如果我从主屏幕(选项卡)移至任何其他选项卡。我应该清除堆栈(不是指小部件)。

假设您正在遵循第一个教程。

有 3 个选项卡。Home, Calendar and Profile.

现在从主屏幕我添加了“Screen2“。所以,现在我当前的选项卡是 ”Home“。如果我点击Calendar选项卡我选择的Ttab 是“Calendar".

我将从当前选项卡中弹出所有内容,直到满足第一条路线。一旦完成,我将设置状态。

Code:


void _selectTab(TabItem tabItem) {
    if (tabItem == _currentTab) {
      _navigatorKeys[tabItem]?.currentState?.popUntil((route) => route.isFirst);
    } else {
      //! Added logic to Pop everything from Home tab, if any other tab is clicked
      if (_currentTab == TabItem.HOME) {
        _navigatorKeys[_currentTab]
            ?.currentState
            ?.popUntil((route) => route.isFirst);
      }
      setState(() => _currentTab = tabItem);
    }
  }

我从底部导航调用此方法。

bottomNavigationBar: BottomNavigation(
          currentTab: _currentTab,
          onSelectTab: _selectTab,
        ),

希望这可以帮助。让我知道这是否足够。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flutter:带有嵌套导航的底部导航栏,并在选项卡更改时恢复根页面 的相关文章

随机推荐

  • AngularFire 访问子元素方法

    我正在寻找一种方法来获取子元素的方法 而不是单独加载该元素 假设我有一个帖子模型 每个帖子都有评论 这就是我获取帖子模型的方式 var post firebase new Firebase FIREBASE URL posts post n
  • 如何为 cxf jax-rs 2.0 客户端注册 jackson json 提供程序?

    我有一个 JAX RS 客户端正在发出一个简单的 GET 请求 我使用 CXF 实现和 Spring 进行 DI 呼叫成功 我收到响应代码 200 但是在将响应读入 POJO 时出现错误 例外 2015 05 08 16 11 55 457
  • 如何获取基本表单中继承表单的大小?

    假设您有一个名为FormBase所有其他形式都继承自该形式 例如 我有public class Form formTest FormBase 我现在在 formTest 的 ctor 中拥有什么 public class Form form
  • 基于 JPA 注释生成 ERD(实体关系图)的工具

    我正在使用 ormlite 编写 java 代码 我想知道是否可以从代码中的 JPA 注释生成 ERD 基本上 我需要相反的情况 如何将基于实体的图转换为 JPA java 代码 https stackoverflow com questi
  • 如何使用 KClass 反射在 Kotlin 中区分类和接口

    我正在使用 Kotlins KClass 按名称查找类 如下所示 val i KClass lt gt Class forName SampleClass kotlin 但是 我想省略接口 到目前为止 我通过构造函数区分接口和类 val i
  • Wagtail 自定义管理

    我是 Wagtail 和 Django 开发的新手 如何更改 Wagtail 管理页面的颜色 根据一些问答 我可以通过 core css 更改颜色 但是扫描代码需要很多时间 有一个更简单的方法 您可以注册 Wagtail Hook 在此处阅
  • 当用户打开文件时如何锁定对文件的访问?

    我正在编写一个 C NET 程序 该程序使用 XmlSerializer 对当前用户正在处理的项目与 XML 文件进行序列化和反序列化 这工作正常 但我试图找到一种方法来防止两个用户从网络驱动器打开同一个文件并让一个用户覆盖前一个用户的保存
  • 求不同数量的双打中的平均值

    我有一个双精度数组列表 我需要找到所有数字之间的平均值 arraylist 中 Double 实例的数量不是恒定的 可能是 2 也可能是 90 我已经尝试了几个小时来自己获取算法 但无论如何都无法让它工作 你有什么建议吗 或者也许你可以将我
  • xpath/xslt 确定上下文节点相对于所有同名节点的索引?

    给定下面的模式 以 查询 节点作为上下文 是否可以使用 xpath xslt 确定该 查询 节点相对于文档中所有 查询 节点的索引 而不是相对于其的position 直系兄弟姐妹 TIA Geoff section section
  • Datagrip 中缺少 Git 集成插件?

    有一些我不明白的东西 我在 DataGrip 2016 3 3 JetBrains IDE 中找不到 Git 集成 插件 PyCharm 安装在同一台计算机上 并且具有 Git 集成插件 我还在另一台机器上安装了 DataGrip 插件 但
  • 在 NUnit 测试中使用 WPF 组件 - 如何使用 STA?

    我需要在 NUnit 单元测试中使用一些 WPF 组件 我通过 ReSharper 运行测试 在使用 WPF 对象时失败并出现以下错误 系统 InvalidOperationException 调用线程必须是 STA 因为许多 UI 组件都
  • Cheesesquare:enterAlways 会产生错误的布局

    Adding enterAlways到 Cheesesquare 演示的滚动标志
  • ALLOWED_HOSTS 在部署到 Elastic Beanstalk 的 Django 应用程序中不起作用

    我将 Django 应用程序部署到 AWS Elastic Beanstalk 即使我已将其添加到允许的主机设置中 我仍收到 无效的 HTTP HOST 标头 错误 我收到此错误 Invalid HTTP HOST header recor
  • C# 获取子窗口句柄

    我正在用 C 启动一个进程 然后使用 SendMessage 将 Windows 消息发送到该进程 通常我将消息发送到 Process MainWindowHandle 但在某些情况下 我可能需要找到子窗口句柄并向那里发送消息 我将如何在
  • 如何在 MVC3 Razor 视图中呈现数据表

    我在 xls 电子表格 1 之间有一个可靠且经过测试的导入方法 该方法返回DataTable 我已将其定位在我的服务层中 而不是数据中 因为只有工作簿作为上传文件保存 但现在我想知道在哪里以及如何生成此内容的 HTML 表示形式DataTa
  • NSUInteger 的奇怪行为 - 无法正确转换为浮动

    这是我的情况 这让我发疯 我有一个计数值为 517 的 NSMutableArray 我有一个双精度值 它是我的乘数 double multiplier 0 1223 double result myArray count multipli
  • Xamarin Android Webview Javascript

    我正在尝试通过 Xamarin for Android 创建一个移动应用程序 它有一个显示网站的 WebView 问题是正常按钮会触发 但 javascript 事件不会触发 我已经启用了 Javascript 但没有运气 如何在 Andr
  • 如何在C Sharp中使用unity3d从url下载文件并保存在位置?

    我正在从事 unity3d 项目 我需要从服务器下载一组文件 我使用 C 编写脚本 经过一个小时的谷歌搜索后 由于文档不完善 我还没有找到解决方案 谁能给我从 url 下载文件并将其保存在 unity3d 中的特定位置的示例代码 Unity
  • OpenCV OpenNI 校准kinect

    我使用 home 通过 kinect 进行捕捉 capture retrieve depthMap CV CAP OPENNI DEPTH MAP capture retrieve bgrImage CV CAP OPENNI BGR IM
  • Flutter:带有嵌套导航的底部导航栏,并在选项卡更改时恢复根页面

    我是 Flutter 开发的新手 我已经阅读了多个教程来了解底部导航栏 我已经尝试过这些教程 但无法达到我的要求 我遵循的教程 https codewithandrea com articles multiple navigators bo