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

Flutter:使用NavigationRail路由时如何保留侧边导航栏?

解决Flutter Web中跳转页面保留NavigationRail的问题

你的问题根源是用了全局路由跳转(比如Navigator.push直接打开EventScreen),但NavigationRail是嵌套在MyHomePage的布局里的,跳转后脱离了这个结构自然会丢失Rail。正确的做法是不通过全局路由跳转,而是通过更新MyHomePage的选中索引来切换页面,同时传递事件详情参数,具体实现如下:

1. 修改搜索页面(HomeScreen),添加导航回调

给HomeScreen增加一个回调函数,点击详情按钮时通知父组件切换到Event页面并传递事件ID:

class HomeScreen extends StatelessWidget {
  final void Function(int index, String? eventId) onNavigateToEvent;

  const HomeScreen({super.key, required this.onNavigateToEvent});

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: 5, // 示例事件数量
      itemBuilder: (context, index) {
        final eventId = 'event_$index';
        return ListTile(
          title: Text('事件 $index'),
          trailing: ElevatedButton(
            onPressed: () {
              // 触发回调,通知父组件切换页面并传参
              onNavigateToEvent(1, eventId);
            },
            child: const Text('查看详情'),
          ),
        );
      },
    );
  }
}

2. 更新MyHomePage,处理导航逻辑和参数传递

在MyHomePage的状态类里添加变量存储事件ID,同时修改内容构建逻辑,给对应页面传递参数:

class _MyHomePageState extends State<MyHomePage> {
  int _selectedIndex = 0;
  String? _currentEventId; // 存储当前要查看的事件ID

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          NavigationRail(
            labelType: NavigationRailLabelType.all,
            selectedIndex: _selectedIndex,
            onDestinationSelected: (int index) {
              setState(() {
                _selectedIndex = index;
                // 切换到非Event页面时清空事件ID
                if (index != 1) _currentEventId = null;
              });
            },
            destinations: [
              const NavigationRailDestination(
                icon: Icon(Icons.search),
                label: Text('Search'),
              ),
              const NavigationRailDestination(
                icon: Icon(Icons.smartphone_outlined),
                label: Text('Event'),
              ),
            ],
          ),
          const VerticalDivider(thickness: 1, width: 1),
          Expanded(
            child: _buildContent(),
          ),
        ],
      ),
    );
  }

  Widget _buildContent() {
    switch (_selectedIndex) {
      case 0:
        return HomeScreen(
          onNavigateToEvent: (index, eventId) {
            setState(() {
              _selectedIndex = index;
              _currentEventId = eventId;
            });
          },
        );
      case 1:
        // 给Event页面传递事件ID
        return EventScreen(eventId: _currentEventId);
      default:
        return HomeScreen(onNavigateToEvent: (_, __) {});
    }
  }
}

3. 调整EventScreen,接收并展示详情

让EventScreen接收事件ID参数,根据参数展示对应内容:

class EventScreen extends StatelessWidget {
  final String? eventId;

  const EventScreen({super.key, this.eventId});

  @override
  Widget build(BuildContext context) {
    return Center(
      child: eventId != null
          ? Text('事件详情:$eventId')
          : const Text('请选择一个事件查看详情'),
    );
  }
}

额外说明

如果之前在BackendRouteConfig.routes里配置了EventScreen的全局路由,建议移除该配置,因为现在是通过MyHomePage的索引切换来展示页面,不需要全局跳转。如果需要支持浏览器地址栏路由同步,可以结合GoRouter实现嵌套路由,但对于小型Web应用,上面的回调方式已经足够简单高效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 04:46:23