使用Flutter与GetX实现带参数的子路由导航
GetX 替代 Riverpod+AutoRouter 实现路由导航与滚动定位方案
一、解决GetMaterialApp.router核心问题
1. 避免HomeController重复初始化
不在页面内部重复调用Get.put(HomeController()),全局初始化时一次性注入:
void main() async { WidgetsFlutterBinding.ensureInitialized(); // 全局懒加载控制器,确保仅初始化一次 Get.lazyPut(() => HomeController(), fenix: true); runApp(const MyApp()); }
页面中直接通过Get.find<HomeController>()获取实例,杜绝重复初始化。
2. 改用常规GetMaterialApp配置路由
放弃易引发时序问题的GetMaterialApp.router,直接用getPages配置路由:
class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return GetMaterialApp( title: 'GetX Demo', initialRoute: '/', getPages: [ GetPage(name: '/', page: () => const HomePage()), GetPage(name: '/listView', page: () => const ListViewPage()), ], ); } }
3. 解决PageView滚动控制器重复绑定问题
给每个PageView页面绑定独立控制器,通过GetX依赖注入管理:
// PageView专属控制器 class PageViewController extends GetxController { final ScrollController scrollController = ScrollController(); @override void onClose() { scrollController.dispose(); super.onClose(); } } // PageView页面使用 class PageViewPage extends StatelessWidget { const PageViewPage({super.key}); @override Widget build(BuildContext context) { final controller = Get.put(PageViewController()); return PageView( controller: controller.scrollController, children: const [/* 页面内容 */], ); } }
页面销毁时GetX自动销毁控制器,避免内存泄漏与重复绑定。
二、前台导航传参与滚动定位实现
1. 前台导航传参
从HomePage跳转至ListViewPage并传递索引:
// HomePage中触发导航 Get.toNamed('/listView', arguments: 25);
2. ListView接收参数并滚动定位
通过Get.arguments获取索引,结合ScrollController完成定位:
class ListViewController extends GetxController { final ScrollController scrollController = ScrollController(); // 假设列表项固定高度 final double itemHeight = 60.0; void scrollToIndex(int index) { if (index >= 0) { scrollController.jumpTo(index * itemHeight); // 平滑滚动可替换为:scrollController.animateTo(index * itemHeight, duration: const Duration(milliseconds: 300), curve: Curves.ease); } } } class ListViewPage extends StatelessWidget { const ListViewPage({super.key}); @override Widget build(BuildContext context) { final controller = Get.put(ListViewController()); // 获取导航传递的索引 final int? targetIndex = Get.arguments; // 页面渲染完成后执行滚动 WidgetsBinding.instance.addPostFrameCallback((_) { if (targetIndex != null) { controller.scrollToIndex(targetIndex); } }); return Scaffold( appBar: AppBar(title: const Text('ListView')), body: ListView.builder( controller: controller.scrollController, itemCount: 100, itemBuilder: (_, index) => ListTile(title: Text('Item $index')), ), ); } }
三、Deeplink/通知触发的导航与定位
1. 初始化时处理Deeplink参数
在main函数中先解析Deeplink,再设置初始路由与目标索引:
void main() async { WidgetsFlutterBinding.ensureInitialized(); // 初始化全局控制器 Get.lazyPut(() => HomeController(), fenix: true); // 获取初始Deeplink Uri? initialUri = await getInitialUri(); String initialRoute = '/'; int? targetIndex; if (initialUri != null) { // 解析Deeplink路径与参数 if (initialUri.path == '/listView') { targetIndex = int.tryParse(initialUri.queryParameters['index'] ?? ''); initialRoute = '/listView'; } } // 将目标索引注入ListView控制器 Get.lazyPut(() => ListViewController(targetIndex: targetIndex)); runApp(MyApp(initialRoute: initialRoute)); }
2. 修改ListViewController接收初始化索引
class ListViewController extends GetxController { final ScrollController scrollController = ScrollController(); final double itemHeight = 60.0; final int? initialIndex; ListViewController({this.initialIndex}); @override void onInit() { super.onInit(); // 初始化时自动滚动到指定位置 WidgetsBinding.instance.addPostFrameCallback((_) { if (initialIndex != null) { scrollToIndex(initialIndex!); } }); } void scrollToIndex(int index) { if (index >= 0) { scrollController.jumpTo(index * itemHeight); } } @override void onClose() { scrollController.dispose(); super.onClose(); } }
3. 通知触发的导航逻辑
通知点击时直接调用GetX命名路由并传递参数:
// 通知点击回调 void onNotificationTap(int index) { Get.toNamed('/listView', arguments: index); }
内容的提问来源于stack exchange,提问作者jacob blankenship
相关产品推荐
相关产品推荐

