深入浅出 GetX:超详细实用指南,全方位掌握 Flutter 开发利器第一篇之路由管理篇

557 阅读11分钟

目录

前言

一.安装

二.Getx路由管理

1.普通路由导航

1.导航到新的页面

2.Get.back返回

1.返回上一个页面

2.关闭其它Widget

3.进入下一个页面,但没有返回上一个页面的选项

4.进入下一个界面并取消之前的所有路由

5.跳转到下一个页面并接收会传值

2.别名路由导航

1.别名路由导航

1.导航到下一个页面

2.浏览并删除前一个页面

3.浏览并删除所有以前的页面

4.未定义导航

2.别名路由传值并传值

3.动态网页链接

4.中间件

4.免context导航

1.SnackBars

2.Dialogs

3.BottomSheets

3.嵌套导航

4.完整demo


前言

        正如Get官方介绍,GetX 是 Flutter 上的一个轻量且强大的解决方案:高性能的状态管理、智能的依赖注入和便捷的路由管理。GetX 有3个基本原则:

        性能: GetX 专注于性能和最小资源消耗。

        效率: GetX 的语法非常简捷,并保持了极高的性能,能极大缩短你的开发时长。

        结构: GetX 可以将界面、逻辑、依赖和路由之间低耦合,逻辑更清晰,代码更容易维护。

        这篇文章主要是介绍下GetX的三大核心功能之一的路由管理。

一.安装

        目前get最新的版本是4.6.6。安装方式如下:

dependencies:
get: ^4.6.6

        安装好get之后,最简单的配置就是在你的MaterialApp前面加上 "Get",就可以把它变成GetMaterialApp,下面就可以尽情的使用你的GetX吧。

GetMaterialApp( // Before: MaterialApp(
  home: MyHomePage(),
)

二.Getx路由管理

1.普通路由导航

1.导航到新的页面

        假如我们有一个新页面NextScreenPage,代码如下:

import 'package:flutter/material.dart';

class NextScreenPage extends StatelessWidget {
  const NextScreenPage({super.key});
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text("新页面"),
      ),
      body: Container(
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

        效果图如下:

编辑

        图1.跳转新页面  

2.Get.back返回

        Get.back可以用来关闭SnackBars、Dialogs、BottomSheets或任何你通常会用Navigator.pop(context)关闭的东西。

        我们可以下面的代码来实现相应的功能。

1.返回上一个页面

        还是以上面的代码为例,我们在NextScreen中点击返回按钮的时候,回到当前页面。直接调用Get.back即可:

Get.back();

编辑

       图2.返回上一页

2.关闭其它Widget

        Get.back关闭SnackBars、Dialogs、BottomSheets或任何你通常会用Navigator.pop(context)关闭的东西。

        我们以SnackBar为例,在下面的例子中,我们点击展示SnackBar按钮,StanackBar显示10秒钟,点击关闭SnackBar按钮的时候,调用Get.back即可关闭SnackBar。

        当然其它的Widget例如Dialogs、BottomSheets或任何你通常会用Navigator.pop(context)关闭的东西你都可以调用Get.back来实现。

编辑

图3.关闭SnackBar的例子

3.进入下一个页面,但没有返回上一个页面的选项

         这种场景用于SplashScreens,登录页面等。例如我们第一次进入用户引导页面,下一次直接进入主页。

        以下面的实例为例,我们点击按钮进入下一个页面,然后点击返回按钮直接返回app主页。

Get.off(const NextScreenPage());

编辑

       图4.导航并销毁上一个页面

4.进入下一个界面并取消之前的所有路由

        这个在购物车、投票和测试中很有用。

        如下图5所示,我们点击跳转按钮之后,直接取消之前的所有页面,实现代码如下:

Get.off(const NextScreenPage());

编辑

图5.导航到下一个页面并取消所有路由

5.跳转到下一个页面并接收会传值

        要导航到下一条路由,并在返回后立即接收或更新数据。

 var data = await Get.to(const NextScreenPage());

        在另一个页面上,发送前一个路由的数据。

Get.back(result: 'success');

        效果如下:

编辑

图6.跳转到下一个页面并接收下一页面回传值

2.别名路由导航

1.别名路由导航

        Get支持别名路由,使用别名路由的时候,我们需要在GetMaterialApp定义一下,假如我们有一个NextScreenPage页面,使用别名路由的时候,代码定义如下:

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

import 'home_page.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      initialRoute: '/',
      getPages: [
        GetPage(name: '/NextScreen', page: () => const NextScreenPage()),
      ],
      home: const MyHomePage(),
    );
  }
}

1.导航到下一个页面

Get.toNamed("/next_screen");

2.浏览并删除前一个页面

Get.offNamed("/next_screen");

3.浏览并删除所有以前的页面

Get.offAllNamed("/NextScreen");

4.未定义导航

        为了防止我们导航到未定义的页面,我们可以在GetMaterialApp中定义unknownRoute页面。

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:getx_route_management/404_page.dart';
import 'package:getx_route_management/next_screen_page.dart';

import 'home_page.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      unknownRoute: GetPage(name: '/not_found', page: ()=>const UnknownRoutePage()),
      initialRoute: '/',
      getPages: [
        GetPage(name: '/NextScreen', page: () => const NextScreenPage()),
      ],
      home: const MyHomePage(),
    );
  }
}

        这样当我们通过别名路由方式跳转的时候,如果路由的名称写错了,会自动导航到我们定义的404路由页面。

编辑

图7.404路由页面        

2.别名路由传值并传值

        只要发送你想要的参数即可。Get在这里接受任何东西,无论是一个字符串,一个Map,一个List,甚至一个类的实例。

Get.toNamed("/NextScreen", arguments: 'Get is the best');

        在你的类或控制器上:

print(Get.arguments);
//print out: Get is the best

3.动态网页链接

        Get提供高级动态URL,就像在Web上一样。

Get.offAllNamed("/NextScreen?device=phone&id=354&name=Enzo");

        第二个页面获取数据:

debugPrint("id = Get.parameters[id]");debugPrint("device={Get.parameters['id']} "); debugPrint("device = {Get.parameters['device']} ");
debugPrint("name = ${Get.parameters['name']} ");

4.中间件

        受制于文章篇幅,这里专门写了一篇Getx鉴权的博客,有兴趣的同学们可以查看下。

4.免context导航

        使用GetX我们可以避免使用Flutter非常多的代码去实现SnackBar、Dialogs、BottomSheets。

        下面我们看具体的用法:

1.SnackBars

        GetX创建一个SnackBars代码如下:

Get.snackbar('SnackBar', '我是SnackBar');

编辑

        图7.Getx免context导航

        OK,就这么一行代码,我们就轻松的实现了SnackBar。

        我们看看Flutter怎么实现这个功能:

        用Flutter创建一个简单的SnackBar,你必须获得Scaffold的context,或者你必须使用一个GlobalKey附加到你的Scaffold上。

final snackBar = SnackBar(
content: Text('Hi!'),
action: SnackBarAction(
label: 'I am a old and ugly snackbar :(',
onPressed: (){}
),
);
// 在小组件树中找到脚手架并使用它显示一个SnackBars。
Scaffold.of(context).showSnackBar(snackBar);

        这么一对比,看看Getx提高了多少效率。

        当然这里仅仅是演示getX的用法,具体使用SnackBar的定制,您可以看一下它的源码。

2.Dialogs

        同样我们使用defaultDialog和dialog也不需要context。

        仅仅需要一行代码即可。

        打开Dialogs:

Get.dialog(YourDialogWidget());

        打开默认Dialogs代码如下:

Get.defaultDialog(
onConfirm: () => debugPrint("Ok"),
middleText: "我是Dialog"
);

编辑

        图8.免dialogs导航

3.BottomSheets

        Get.bottomSheet类似于showModalBottomSheet,但不需要context:

Get.bottomSheet(
Wrap(
children: <Widget>[
ListTile(
leading: const Icon(Icons.music_note),
title: const Text('Music'),
onTap: () {}
),
ListTile(
leading: const Icon(Icons.videocam),
title: const Text('Video'),
onTap: () {},
),
],
)
);

        效果图如下:

编辑

图9.免BottomSheets导航

5.嵌套导航

        Get让Flutter的嵌套导航更加简单。 你不需要context,而是通过Id找到你的导航栈。

Navigator(
key: Get.nestedKey(1), // create a key by index
initialRoute: '/',
onGenerateRoute: (settings) {
if (settings.name == '/') {
return GetPageRoute(
page: () => Scaffold(
appBar: AppBar(
title: Text("Main"),
),
body: Center(
child: TextButton(
color: Colors.blue,
onPressed: () {
Get.toNamed('/second', id:1); // navigate by your nested route by index
},
child: Text("Go to second"),
),
),
),
);
} else if (settings.name == '/second') {
return GetPageRoute(
page: () => Center(
child: Scaffold(
appBar: AppBar(
title: Text("Main"),
),
body: Center(
child:  Text("second")
),
),
),
);
}
}
),

3.嵌套导航

        Get让Flutter的嵌套导航更加简单。 你不需要context,而是通过Id找到你的导航栈。

  • 注意:创建平行导航堆栈可能是危险的。理想的情况是不要使用NestedNavigators,或者尽量少用。如果你的项目需要它,请继续,但请记住,在内存中保持多个导航堆栈可能不是一个好主意(消耗RAM)。

看看它有多简单:

Navigator(
key: Get.nestedKey(1), // create a key by index
initialRoute: '/',
onGenerateRoute: (settings) {
if (settings.name == '/') {
return GetPageRoute(
page: () => Scaffold(
appBar: AppBar(
title: Text("Main"),
),
body: Center(
child: TextButton(
color: Colors.blue,
onPressed: () {
Get.toNamed('/second', id:1); // navigate by your nested route by index
},
child: Text("Go to second"),
),
),
),
);
} else if (settings.name == '/second') {
return GetPageRoute(
page: () => Center(
child: Scaffold(
appBar: AppBar(
title: Text("Main"),
),
body: Center(
child:  Text("second")
),
),
),
);
}
}
),

4.完整demo

        本文用到的demo这里