GetX:onGenerateRoute 的工作原理

案例代码

完整代码

import 'package:flutter/material.dart';
import 'package:get/get.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    // MaterialApp 换成 GetMaterialApp
    return GetMaterialApp(
      title: 'Navigator 1.0 + GetX 嵌套导航 Demo',
      home: const MainPage(),
    );
  }
}

class MainPage extends StatefulWidget {
  const MainPage({super.key});

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  int _index = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("GetX+Navigator 1.0 嵌套导航 Demo")),
      body: IndexedStack(
        index: _index,
        children: const [Tab1Page(), Tab2Page()],
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _index,
        onTap: (i) => setState(() => _index = i),
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: "Tab1"),
          BottomNavigationBarItem(icon: Icon(Icons.settings), label: "Tab2"),
        ],
      ),
    );
  }
}

class Tab1Page extends StatelessWidget {
  const Tab1Page({super.key});

  @override
  Widget build(BuildContext context) {
    // 从 GetX 4.6.x 之后,GetNavigator 就逐渐和 Flutter 原生的 Navigator 2.0 完全对齐,
    // 因此现在不再支持onGenerateRoute这个参数,如果想用只能通过Navigator
    return Navigator(
      key: Get.nestedKey(1),
      onGenerateRoute: (settings) {
        if (settings.name == "/tab1/detail") {
          return MaterialPageRoute(builder: (_) => const DetailPage());
        }
        return MaterialPageRoute(builder: (_) => const Tab1Home());
      },
    );
  }
}

class Tab1Home extends StatelessWidget {
  const Tab1Home({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Tab1 首页")),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            // ✅ GetX 的跳转方式
            Get.toNamed("/tab1/detail", id: 1);
            // Get.to(
            //   () => const DetailPage(),
            //   id: 1, // 注意指定子导航器 ID
            // );
            // 这里的 id:1 是对应 Tab1Page 里的 Navigator
          },
          child: const Text("进入详情页"),
        ),
      ),
    );
  }
}

class DetailPage extends StatelessWidget {
  const DetailPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("详情页")),
      body: Center(
        child: ElevatedButton(
          onPressed: () => Get.back(id: 1), // ✅ 返回 Tab1 的路由栈
          child: const Text("返回 Tab1"),
        ),
      ),
    );
  }
}

class Tab2Page extends StatelessWidget {
  const Tab2Page({super.key});

  @override
  Widget build(BuildContext context) {
    return Navigator(
      key: Get.nestedKey(2), // ✅ 指定子导航器 ID 为 2
      onGenerateRoute: (settings) {
        // 这里始终返回 Tab2 首页
        return MaterialPageRoute(builder: (_) => const Tab2Home());
      },
    );
  }
}

class Tab2Home extends StatelessWidget {
  const Tab2Home({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Tab2 页面")),
      body: const Center(child: Text("这里是 Tab2")),
    );
  }
}

关键代码截图

class Tab1Page extends StatelessWidget {
  const Tab1Page({super.key});

  @override
  Widget build(BuildContext context) {
    // 从 GetX 4.6.x 之后,GetNavigator 就逐渐和 Flutter 原生的 Navigator 2.0 完全对齐,
    // 因此现在不再支持onGenerateRoute这个参数,如果想用只能通过Navigator
    return Navigator(
      key: Get.nestedKey(1),
      onGenerateRoute: (settings) {
        if (settings.name == "/tab1/detail") {
          return MaterialPageRoute(builder: (_) => const DetailPage());
        }
        return MaterialPageRoute(builder: (_) => const Tab1Home());
      },
    );
  }
}

// ✅ GetX 的跳转方式
Get.toNamed("/tab1/detail", id: 1);
// Get.to(
//   () => const DetailPage(),
//   id: 1, // 注意指定子导航器 ID
// );
// 这里的 id:1 是对应 Tab1Page 里的 Navigator


() => Get.back(id: 1), // ✅ 返回 Tab1 的路由栈

onGenerateRoute 是什么

在 Flutter 中,Navigator 是一个路由栈管理器,管理着一组页面的进出。

当你创建一个 Navigator 并提供了 onGenerateRoute 参数时,它会在「需要创建路由时」调用 onGenerateRoute生成一个页面(Route 对象)

工作流程

应用创建 Navigator

Navigator(
  key: Get.nestedKey(1),
  onGenerateRoute: (settings) {
    return MaterialPageRoute(builder: (_) => const Tab1Home());
  },
);

简图:

[App 启动]
     ↓
[创建 Navigator (id=1)]
     ↓
[配置 onGenerateRoute 回调函数]

第一次显示页面时调用 onGenerateRoute

当这个 Navigator 创建时,它会调用一次 onGenerateRoute,并传入一个默认的 RouteSettings(通常 name=nullname="/")。

此时 onGenerateRoute 返回一个 MaterialPageRoute,例如:

MaterialPageRoute(builder: (_) => const Tab1Home());

简图:

[Navigator 需要显示第一个页面]
     ↓
[调用 onGenerateRoute(settings)]
     ↓
[返回一个 MaterialPageRoute(Tab1Home)]
     ↓
[Tab1Home 被压入路由栈并显示]

当调用 Navigator.pushNamed(...)

如果你调用:

Navigator.of(context).pushNamed("/tab1/detail");

或者 Get.toNamed("/tab1/detail", id: 1);

则会再次调用 onGenerateRoute,这次传入的 settings.name == "/tab1/detail"

你的代码中会判断:

if (settings.name == "/tab1/detail") {
  return MaterialPageRoute(builder: (_) => const DetailPage());
}

于是 DetailPage 被创建并压入当前 Navigator 的路由栈中。

简图:

[调用 pushNamed("/tab1/detail")]
     ↓
[调用 onGenerateRoute(settings.name = "/tab1/detail")]
     ↓
[返回一个 MaterialPageRoute(DetailPage)]
     ↓
[DetailPage 被压入当前 Navigator 的路由栈]

Get.to(...) 不会触发onGenerateRoute

return Navigator(
  key: Get.nestedKey(1),
  onGenerateRoute: (settings) {
    if (settings.name == "/tab1/detail") {
      return MaterialPageRoute(builder: (_) => const DetailPage());
    }
    return MaterialPageRoute(builder: (_) => const Tab1Home());
  },
);

当如果不使用Get.toNamed,而使用Get.to

Get.to(() => const DetailPage(), id: 1);

GetX 会直接找到 id=1Navigator,然后直接调用它的 push() 方法,压入一个新的路由(MaterialPageRoute),而不是通过 onGenerateRoute

也就是说:

  • Get.to(() => const DetailPage(), id: 1) 并不会走 onGenerateRoute
  • 它直接用你传入的 WidgetDetailPage)创建一个新的 MaterialPageRoute,然后直接 push 进路由栈。

简图:

[Get.to(() => DetailPage(), id: 1)]
     ↓
[找到 Navigator(key: Get.nestedKey(1))]
     ↓
[直接 push 一个 MaterialPageRoute(DetailPage)]
     ↓
[DetailPage 出现在 Tab1 的 Navigator 中]

所以上面的代码可以简化为:

Navigator(
  key: Get.nestedKey(1),
  onGenerateRoute: (settings) {
    return MaterialPageRoute(builder: (_) => const Tab1Home());
  },
);

只保留初始页面的生成逻辑就够了。

×

喜欢就点赞,疼爱就打赏