You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Flutter实现类YouTube式底部导航及子页面状态留存

实现YouTube风格的Flutter底部导航(带独立导航栈+状态保存)

当然可行!这种每个主页面拥有独立导航栈、切换时保存子页面状态的底部导航,是Flutter里非常常见的需求,完全能实现,和你提到的Material Design规范完全匹配。我之前做过类似的实现,下面给你详细讲下思路和代码示例:

核心思路

要实现这种效果,关键在于给每个底部导航项分配独立的Navigator导航栈,同时用IndexedStack来保留所有主页面的状态(避免切换时重建页面)。这样每个主页面下的子页面跳转都在自己的栈里,切换底部导航时,之前的子页面状态会被完整保存。

具体实现步骤

1. 定义底部导航项与导航键

首先我们需要三个底部导航项(对应Home、Shorts、Subscriptions),同时给每个导航栈分配一个GlobalKey<NavigatorState>,用来单独控制每个栈的跳转行为:

int _currentIndex = 0;
final List<GlobalKey<NavigatorState>> _navigatorKeys = [
  GlobalKey<NavigatorState>(),
  GlobalKey<NavigatorState>(),
  GlobalKey<NavigatorState>(),
];

2. 用IndexedStack承载所有主页面

IndexedStack会根据当前索引显示对应的页面,并且保留所有子Widget的状态,不会因为切换而销毁:

body: IndexedStack(
  index: _currentIndex,
  children: [
    _buildNavigator(_navigatorKeys[0], const HomePage()),
    _buildNavigator(_navigatorKeys[1], const ShortsPage()),
    _buildNavigator(_navigatorKeys[2], const SubscriptionsPage()),
  ],
),

3. 构建独立导航栈

每个主页面都嵌套一个Navigator,处理该页面下的子页面跳转:

Widget _buildNavigator(GlobalKey<NavigatorState> key, Widget initialPage) {
  return Navigator(
    key: key,
    initialRoute: '/',
    onGenerateRoute: (settings) {
      return MaterialPageRoute(
        builder: (context) {
          switch (settings.name) {
            case '/':
              return initialPage;
            // Home页面的子页面示例
            case '/home-detail':
              return const HomeDetailPage();
            // Shorts页面的子页面示例
            case '/short-detail':
              return const ShortDetailPage();
            // Subscriptions页面的子页面示例
            case '/sub-detail':
              return const SubDetailPage();
            default:
              return initialPage;
          }
        },
      );
    },
  );
}

4. 处理底部导航点击事件

实现和YouTube一致的行为:点击当前选中的底部项时,回到该导航栈的根页面;点击其他项时切换页面并保留原页面状态:

bottomNavigationBar: BottomNavigationBar(
  currentIndex: _currentIndex,
  onTap: (index) {
    if (index == _currentIndex) {
      // 点击当前页面,回到根路由
      _navigatorKeys[index].currentState?.popUntil((route) => route.isFirst);
    } else {
      setState(() {
        _currentIndex = index;
      });
    }
  },
  items: const [
    BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
    BottomNavigationBarItem(icon: Icon(Icons.play_arrow), label: 'Shorts'),
    BottomNavigationBarItem(icon: Icon(Icons.subscriptions), label: 'Subs'),
  ],
),

关键细节说明

  • 状态保存:IndexedStack会保留所有主页面的Widget状态,包括每个导航栈的当前路由、页面滚动位置、输入框内容等,完全符合你的需求。
  • 独立导航栈:每个主页面的子页面跳转互不干扰,比如在Home的详情页切换到Shorts,再切回Home时依然停留在详情页。
  • Material Design规范匹配:这种实现完全对应你提到的Bottom Navigation Behavior示例,和YouTube的交互逻辑一致。

如果你需要在子页面里跳转,只需要调用当前导航栈的push方法即可,比如在HomePage里:

Navigator.of(context).pushNamed('/home-detail');

内容的提问来源于stack exchange,提问作者Micha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:54:23