Flutter Curved Navigation Bar动画不同步及断言错误求助
问题描述
点击Curved Navigation Bar图标时页面可正常切换,但导航栏动画未同步更新。例如点击confirmation_num图标跳转至TicketScreen后,导航栏仍停留在首页选项;尝试更换其他导航栏组件时持续出现断言错误,期望导航栏动画与页面切换保持同步。
问题原因分析
- 页面跳转导致状态丢失:使用
Navigator.push跳转新页面时,原页面的导航栏组件被压入栈中,新页面的导航栏(若存在)是独立实例,无法共享原有currentIndex状态,导致视觉上导航栏未同步。 - 状态管理冲突:同时维护本地
currentIndex和NavigationBarController状态,两者未双向同步,且跳转后未同步新页面导航栏的选中状态。 - 错误的页面切换逻辑:底部导航栏对应的页面不应通过
push/pushReplacement跳转,而应通过根容器管理页面切换,保持导航栏始终在页面栈的根位置,避免状态丢失。
解决方案
1. 重构页面结构,用根容器统一管理导航栏与页面
将底部导航栏放在根页面中,通过条件渲染切换页面,替代Navigator跳转,确保导航栏状态始终稳定。
2. 同步控制器与本地状态
监听NavigationBarController的状态变化,同步更新导航栏的选中索引,避免状态不一致。
3. 修复图标选中状态的视觉区分
修正原代码中图标颜色无差异的问题,明确区分选中与未选中状态。
修改后的完整代码
import 'package:curved_navigation_bar/curved_navigation_bar.dart'; import 'package:flutter/material.dart'; import 'package:rts_mvc_version_1/controllers/bottom_navigation_bar_controller.dart'; import '../../controllers/home_controller.dart'; import '../../models/home_model.dart'; import '../../models/user_repo_model.dart'; import '../../views/home_screen.dart'; import '../../views/ticket_screen.dart'; import '../service/api_client.dart'; class RootContainerScreen extends StatefulWidget { const RootContainerScreen({super.key}); @override State<RootContainerScreen> createState() => _RootContainerScreenState(); } class _RootContainerScreenState extends State<RootContainerScreen> { final NavigationBarController _controller = NavigationBarController(); int _currentIndex = 2; // 初始化页面所需实例 final HomeModel homeModel = HomeModel(); late final HomeController homeController; final UserRepository userRepository = UserRepository(); final ApiClient apiClient = ApiClient(); @override void initState() { super.initState(); homeController = HomeController(homeModel, () => setState(() {})); _controller.setIndex(_currentIndex); // 监听控制器状态变化,同步本地索引 _controller.addListener(() { if (_currentIndex != _controller.selectedIndex) { setState(() { _currentIndex = _controller.selectedIndex; }); } }); } // 根据当前索引返回对应页面 Widget _getCurrentPage() { switch (_currentIndex) { case 0: return const Center(child: Text("通知页面")); case 1: return TicketScreen(); case 2: return HomeScreen( homeModel, homeController, userRepository, apiClient, ); case 3: return const Center(child: Text("个人中心")); case 4: return const Center(child: Text("支付页面")); default: return const SizedBox.shrink(); } } @override Widget build(BuildContext context) { return Scaffold( body: _getCurrentPage(), bottomNavigationBar: CurvedNavigationBar( backgroundColor: Colors.transparent, color: const Color(0xFF273989), animationDuration: const Duration(milliseconds: 300), index: _currentIndex, onTap: (index) { _controller.setIndex(index); setState(() { _currentIndex = index; }); }, items: [ Icon( Icons.notifications, color: _currentIndex == 0 ? Colors.yellow : Colors.white, ), Icon( Icons.confirmation_num, color: _currentIndex == 1 ? Colors.yellow : Colors.white, ), Icon( Icons.home_filled, color: _currentIndex == 2 ? Colors.yellow : Colors.white, ), Icon( Icons.person, color: _currentIndex == 3 ? Colors.yellow : Colors.white, ), Icon( Icons.credit_card, color: _currentIndex == 4 ? Colors.yellow : Colors.white, ), ], ), ); } }
关键修改点
- 根容器设计:新增
RootContainerScreen作为导航栏和页面的统一容器,避免页面跳转导致导航栏状态丢失。 - 页面切换逻辑:通过
_getCurrentPage()根据索引渲染对应页面,替代Navigator跳转,保持导航栏始终可见且状态同步。 - 状态双向同步:监听控制器状态变化,自动更新本地索引,确保控制器与导航栏状态一致。
- 视觉状态修复:将选中图标改为黄色(可自定义),明确区分选中状态。
- 冗余代码清理:删除重复的状态设置调用,简化逻辑层级。
内容的提问来源于stack exchange,提问作者wasyabi
相关产品推荐
相关产品推荐

