Flutter:使用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
相关产品推荐
相关产品推荐

