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

使用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')),
      ),
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 16:02:51