您的当前位置:首页正文

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

2024-11-13 来源:个人技术集锦

前言

一.安装

二.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。安装方式如下:

        安装好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['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在这里。

Top