Flutter go_router ShellRoute builder键盘弹出时多次调用问题求助
解决GoRouter ShellRoute Builder在键盘弹出时多次调用的问题
问题场景
使用GoRouter的ShellRoute时,当TextFormField获取焦点、键盘弹出,ShellRoute的builder函数会被多次调用,需要让该函数内的逻辑仅执行一次。
原因分析
键盘弹出会触发屏幕布局尺寸变化(MediaQuery更新),导致Flutter Widget树重建,ShellRoute的builder作为布局的一部分会被重新调用。如果builder中包含副作用逻辑(如打印、网络请求),就会重复执行。
解决方案
将ShellRoute的builder返回内容封装为独立的StatefulWidget,把需要仅执行一次的逻辑放到组件的initState方法中,并通过AutomaticKeepAliveClientMixin保持组件状态,避免不必要的重建执行。
修改后的代码示例
仅需修改main.dart内容,其他文件保持不变:
import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'debug_focus_page.dart'; import 'init_page.dart'; final _rootNavigatorKey = GlobalKey<NavigatorState>(); final _debugNavigatorKey = GlobalKey<NavigatorState>(); final _router = GoRouter(debugLogDiagnostics: true, initialLocation: "/init", navigatorKey: _rootNavigatorKey, routes: [ GoRoute(path: '/init', builder: (context, state) => const InitPage()), ShellRoute( navigatorKey: _debugNavigatorKey, builder: (context, state, child) => ShellContainer(child: child), routes: [ GoRoute( path: '/debugFocus', builder: (context, state) => const DebugFocusPage(), ) ]) ]); void main() { runApp(const HomePage()); } class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Debug Autofocus', home: MaterialApp.router( routerConfig: _router, theme: ThemeData( primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ) ), ); } } // 自定义Shell容器,实现状态保持 class ShellContainer extends StatefulWidget { final Widget child; const ShellContainer({super.key, required this.child}); @override State<ShellContainer> createState() => _ShellContainerState(); } class _ShellContainerState extends State<ShellContainer> with AutomaticKeepAliveClientMixin { @override void initState() { super.initState(); // 仅执行一次的逻辑放在这里 print('ssssss'); } @override Widget build(BuildContext context) { super.build(context); // 必须调用以启用状态保持 return Scaffold( appBar: AppBar(), body: widget.child, ); } @override bool get wantKeepAlive => true; // 开启状态保持 }
关键说明
- 将原ShellRoute builder中的UI和副作用逻辑拆分到
ShellContainer组件,仅执行一次的代码(如打印)移至initState,该方法仅在组件初始化时执行一次。 - 通过
AutomaticKeepAliveClientMixin和wantKeepAlive: true,确保组件在键盘弹出等布局变化时不会被重建,避免重复执行初始化逻辑。
内容的提问来源于stack exchange,提问作者billcyz
相关产品推荐
相关产品推荐

