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

使用go_router搭配BottomNavigationWidget时非调试模式导航失效

问题分析与解决方案

问题根源

你的代码存在三个核心问题导致非调试模式导航失效:

  1. 导航方式混用:底部导航中Product项用了router.go('/product'),其他项用context.go,非调试模式下router实例的上下文绑定可能出现异常,导致导航不生效。
  2. 页面重复嵌入底部导航:每个页面(Home/Product等)都单独添加了BottomNavigationWidget,切换页面时会重建整个Scaffold,破坏了go_router的路由栈逻辑。
  3. 未使用ShellRoute管理底部导航:go_router实现底部导航的标准方式是用ShellRoute创建常驻的导航外壳,你的路由结构是独立的页面路由,不符合底部导航的场景需求。

修复步骤与代码示例

1. 修改路由配置,使用ShellRoute重构结构

将所有页面路由作为ShellRoute的子路由,让底部导航成为常驻的外壳组件:

import 'package:bops_app_v3/screens/add_screen.dart';
import 'package:bops_app_v3/screens/home_screen.dart';
import 'package:bops_app_v3/screens/product_screen.dart';
import 'package:bops_app_v3/screens/profile_screen.dart';
import 'package:bops_app_v3/widget/botton_navegation_widget.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

final router = GoRouter(routes: [
  ShellRoute(
    builder: (context, state, child) {
      // 外壳组件:包含底部导航,子页面作为body内容
      return Scaffold(
        body: child,
        bottomNavigationBar: const BottomNavigationWidget(),
      );
    },
    routes: [
      GoRoute(
        path: '/',
        builder: (context, state) => const HomeScreen(),
      ),
      GoRoute(
        path: '/product',
        builder: (context, state) => const ProductScreen(),
      ),
      GoRoute(
        path: '/add',
        builder: (context, state) => const AddScreen(),
      ),
      GoRoute(
        path: '/profile',
        builder: (context, state) => const ProfileScreen(),
      ),
    ],
  ),
]);

2. 统一底部导航的导航方式并同步选中状态

修改BottomNavigationWidget,全部使用context.go,同时新增方法同步当前路由对应的选中索引:

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

class BottomNavigationWidget extends StatelessWidget {
  const BottomNavigationWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return BottomNavigationBar(
      selectedItemColor: Colors.blue,
      unselectedItemColor: Colors.black,
      currentIndex: _getCurrentIndex(context),
      onTap: (index) {
        switch (index) {
          case 0:
            context.go('/');
            break;
          case 1:
            context.go('/product');
            break;
          case 2:
            context.go('/add');
            break;
          case 3:
            context.go('/profile');
            break;
        }
      },
      items: const [
        BottomNavigationBarItem(icon: Icon(Icons.home_outlined), label: 'Home'),
        BottomNavigationBarItem(
            icon: Icon(Icons.production_quantity_limits_outlined),
            label: 'Product'),
        BottomNavigationBarItem(icon: Icon(Icons.add_outlined), label: 'Add'),
        BottomNavigationBarItem(
            icon: Icon(Icons.person_2_outlined), label: 'Profile'),
      ],
    );
  }

  // 根据当前路由获取底部导航选中索引
  int _getCurrentIndex(BuildContext context) {
    final location = GoRouterState.of(context).location;
    switch (location) {
      case '/':
        return 0;
      case '/product':
        return 1;
      case '/add':
        return 2;
      case '/profile':
        return 3;
      default:
        return 0;
    }
  }
}

3. 修改页面组件,移除重复的底部导航

以HomeScreen为例,其他页面做同样修改:

import 'package:flutter/material.dart';

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: const Text('Home screen'),
      // 移除重复的底部导航配置
    );
  }
}

修复原理

  • ShellRoute创建了一个常驻的页面外壳,底部导航只会初始化一次,切换页面时仅替换child(即各个页面的body),符合底部导航的交互逻辑。
  • 统一使用context.go确保导航上下文与当前页面绑定,避免了非调试模式下的路由实例上下文异常。
  • 新增的_getCurrentIndex方法让底部导航的选中状态与当前路由同步,提升用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 20:34:58