AutoRouter BottomNavigationBar重复渲染及页面多次Build问题的修复咨询
看起来你在使用AutoRouter开发Flutter应用时,碰到了底部导航栏重复绘制、部分页面多次触发build方法的问题,结合你给出的代码和修复方案,我来帮你梳理下问题根因和解决思路:
问题根因分析
从你提供的原始路由配置(app_router.dart)可以看到,RootRoute作为HomeRoute的子路由,同时自身还嵌套了DictionaryRoute和OwnDictionaryRoute两个子路由:
// 原始问题路由配置 part 'app_router.gr.dart'; /// [AppRouter] is the router of the app @AutoRouterConfig(replaceInRouteName: AppRouter._replaceInRouteName) final class AppRouter extends _$AppRouter { static const _replaceInRouteName = 'View,Route'; @override List<AutoRoute> get routes => [ AutoRoute( page: HomeRoute.page, initial: true, children: [ AutoRoute( page: RootRoute.page, children: [ AutoRoute(page: DictionaryRoute.page), AutoRoute(page: OwnDictionaryRoute.page), ], ), ], ), AutoRoute(page: OTPRoute.page), AutoRoute(page: PhoneNumberVerificationRoute.page), AutoRoute(page: SignUpRoute.page), ]; }
而RootView中使用了AutoTabsScaffold来管理底部导航,这种路由嵌套+AutoTabsScaffold路由容器的组合,会导致路由被重复加载,进而触发底部导航栏重复绘制,同时页面的build方法也会因为路由层级的重复初始化而被多次调用(从你debugPrint的日志也能验证这一点)。
修复方案及代码调整
你给出的修复后的路由配置已经命中了问题核心,只需要调整路由的嵌套层级,把DictionaryRoute和OwnDictionaryRoute从RootRoute的子路由中移出,和RootRoute同级,作为HomeRoute的直接子路由即可:
修复后的路由配置(app_router.dart)
/// [AppRouter] is the router of the app @AutoRouterConfig(replaceInRouteName: AppRouter._replaceInRouteName) final class AppRouter extends _$AppRouter { static const _replaceInRouteName = 'View,Route'; @override List<AutoRoute> get routes => [ AutoRoute( page: HomeRoute.page, initial: true, children: [ AutoRoute(page: RootRoute.page), AutoRoute(page: DictionaryRoute.page), AutoRoute(page: OwnDictionaryRoute.page), ], ), AutoRoute(page: OTPRoute.page), AutoRoute(page: PhoneNumberVerificationRoute.page), AutoRoute(page: SignUpRoute.page), ]; }
关键修改点说明
- 移除了
RootRoute内部的子路由配置,将DictionaryRoute、OwnDictionaryRoute提升为HomeRoute的直接子路由 - 这样
RootView中的AutoTabsScaffold可以直接管理这两个路由,不会因为路由嵌套导致重复初始化,从根源上解决底部导航栏重复绘制和页面多次build的问题
配套的页面代码参考
为了让你更清晰地看到完整上下文,这里整理你提供的相关页面代码:
home_view.dart
/// [HomeView] is the view of home page @RoutePage() final class HomeView extends StatelessWidget { /// Constructor const HomeView({super.key}); @override Widget build(BuildContext context) { debugPrint('HomeView build'); context.read<ProductViewModel>().checkSignIn(); return BlocSelector<ProductViewModel, ProductState, bool>( selector: (state) { return state.isSignedIn; }, builder: (context, state) { return state ? const RootView() : const SignUpView(); }, ); } }
root_view.dart
/// [RootView] is the view of root page @RoutePage() final class RootView extends StatelessWidget { /// Constructor const RootView({super.key}); @override Widget build(BuildContext context) { debugPrint('RootView build'); return AutoTabsScaffold( routes: const [ DictionaryRoute(), OwnDictionaryRoute(), ], bottomNavigationBuilder: (_, tabsRouter) { return BottomNavigationBar( currentIndex: tabsRouter.activeIndex, onTap: tabsRouter.setActiveIndex, items: const [ BottomNavigationBarItem( icon: Icon(Icons.search_outlined), label: 'Dictionary', ), BottomNavigationBarItem( icon: Icon(Icons.list_outlined), label: 'Own Dictionary', ), ], ); }, ); } }
dictionary_view.dart
/// [DictionaryView] is the view of dictionary page @RoutePage() final class DictionaryView extends StatefulWidget { /// Constructor const DictionaryView({super.key}); @override State<DictionaryView> createState() => _DictionaryViewState(); } class _DictionaryViewState extends State<DictionaryView> with DictionaryViewMixin { @override Widget build(BuildContext context) { debugPrint('DictionaryView build'); return BlocProvider( create: (context) => dictionaryViewModel, child: BaseView( onPageBuilder: (context, value) => SliverList( delegate: SliverChildListDelegate( [ _DictionaryBody( dictionaryViewModel: dictionaryViewModel, searchController: searchController, ), ], ), ), ), ); } }
修复完成后,你可以通过debugPrint的日志验证:页面的build方法只会在必要时触发一次,底部导航栏也不会再出现重复绘制的情况了。
备注:内容来源于stack exchange,提问作者TheSylar
相关产品推荐
相关产品推荐

