Flutter中GetX的用法(路由管理)

目录

前言

一.安装

二.从一个计时器开始

三.Getx路由管理

1.普通路由导航

1.导航到新的页面

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

3.进入下一个页面,但没有返回上一个页面的选项(用于SplashScreens,登录页面等)

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

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

2.别名路由导航

1.导航到下一个页面

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

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

4.别名路由传值

5.动态网页链接

3.中间件

4.免context导航

1.SnackBars

2.Dialogs

3.BottomSheets

四.文章中的完整demo


前言

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

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

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

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

这篇文章主要是介绍下GetX的用法。

一.安装

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

dependencies:

get: ^4.6.6

二.从一个计时器开始

但我们创建一个flutter工程的时候,系统会生成一个计时器的示例代码,代码大致如下(我删除了部分注释代码):

Dart 复制代码
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

主要功能是点击+按钮,每次计时器的个数+1.点击按钮之后,调用setState方法刷新_counter变量。

下面我们看一下如何使用getx来实现上述的功能:

第一步:把系统的MaterialApp改成GetMaterialApp:

void main() => runApp(GetMaterialApp(home: Home()));

第二步:创建业务类,我们把_counter变量放在Controller类中:

class Controller extends GetxController{

var counter = 0.obs;

increment() => counter++;

}

第三步:使用StatelessWidget代替StatefulWidget,节省下内存。修改之后的完整代码如下:

Dart 复制代码
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) {
    return GetMaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
class Controller extends GetxController{
  var counter = 0.obs;
  incrementCounter()=>counter++;
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  Widget build(BuildContext context) {
    final Controller controller = Get.put(Controller());

    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Obx(() => Text(
              '${controller.counter}',
              style: Theme.of(context).textTheme.headlineMedium,
            )),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          controller.incrementCounter();
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

三.Getx路由管理

1.普通路由导航

1.导航到新的页面

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

Dart 复制代码
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.
    );
  }
}

从当前页面跳转到NextScreenPage页面,代码如下:

Get.to(()=>NextScreen());

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

还是以上面的代码为例,我们添加一个返回按钮,点击返回按钮的时候,回到当前页面。主需要在按钮的点击事件中添加如下代码即可:

Get.back();

NextScreenPage页面完整代码如下:

Dart 复制代码
import 'package:flutter/material.dart';
import 'package:get/get.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: Center(
        child: ElevatedButton(onPressed: (){
          Get.back();
        }, child: const Text("返回上一个页面")),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}
3.进入下一个页面,但没有返回上一个页面的选项(用于SplashScreens,登录页面等)

主要的代码如下:

Get.off(()=>const NormalRoutePage(title: "主页面"));

这里我们模拟一个登陆页面的场景,假设当前页面(NormalRoutePage)有一个按钮,点击按钮之后,我们跳转到登陆页面(LoginPage),登陆成功之后,进入个人中心页面(ProfilePage),这个时候,个人中心页面有个返回按钮,我们点击返回按钮的时候回到主页面,主要的代码如下:

登陆页面代码如下:

Dart 复制代码
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:getx_demos/route_manager/login/profile_page.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text("登陆页面"),
      ),
      body: Center(
        child: ElevatedButton(onPressed: (){
          Get.to(()=>const ProfilePage());
        }, child: const Text("点击进入个人中心页面")),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

个人中心页面代码如下:

Dart 复制代码
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:getx_demos/route_manager/normal_route_page.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text("个人中心页面"),
      ),
      body: Center(
        child: ElevatedButton(onPressed: (){
          Get.off(const NormalRoutePage(title: "主页面"));
        }, child: const Text("返回主页面")),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}
4.进入下一个界面并取消之前的所有路由

Get.offAll(NextScreen());

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

假设当前页面是SecondPage,当我们跳转按钮之后跳转到ThirdPage,按钮的点击事件中我们使用下面的代码获取ThirdPage回传的值:

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

SecondPage页面代码如下:

Dart 复制代码
import 'package:getx_demos/route_manager/login/third_page.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text("回调传值"),
      ),
      body: Column(
        children: [
          Center(
            child: ElevatedButton(onPressed: () async {
              var data = await Get.to(const ThirdPage());
              debugPrint("下个页面回调值:$data");
              Get.to(()=>const ThirdPage());
            }, child: const Text("跳转Third页面")),
          ),
        ],
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

ThirdPage页面代码如下:

Dart 复制代码
import 'package:flutter/material.dart';
import 'package:get/get.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text("Third"),
      ),
      body: Column(
        children: [
          const Text("第二个页面传过来的值:"),
          Center(
            child: ElevatedButton(onPressed: (){
              Get.back(result: "555555");
            }, child: const Text("返回主页面")),
          ),
        ],
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

2.别名路由导航

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

Dart 复制代码
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter Demo',
      initialRoute: "/",
      getPages: [
        GetPage(name: "/next_screen", page: ()=>const NextScreenPage()),
      ],
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
1.导航到下一个页面

Get.toNamed("/next_screen");

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

Get.offNamed("/next_screen");

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

Get.offAllNamed("/next_screen");

4.别名路由传值

Get.toNamed("/rename_main",arguments: "Getx route manager");

5.动态网页链接

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']} ");

3.中间件

如果你想通过监听Get事件来触发动作,你可以使用routingCallback来实现。

复制代码
GetMaterialApp( routingCallback: (routing) { if(routing.current == '/second'){ openAds(); } } )

4.免context导航

如果你想通过监听Get事件来触发动作,你可以使用routingCallback来实现。

1.SnackBars

GetX创建一个SnackBars代码如下:

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

2.Dialogs

打开默认Dialogs:

Get.defaultDialog(

onConfirm: () => debugPrint("Ok"),

middleText: "我是Dialog"

);

3.BottomSheets

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

Dart 复制代码
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: () {},
),
],
)
);

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")

),

),

),

);

}

}

),

四.文章中的完整demo

本文实例中的demo地址。

相关推荐
AiFlutter5 小时前
Flutter之Package教程
flutter
Mingyueyixi9 小时前
Flutter Spacer引发的The ParentDataWidget Expanded(flex: 1) 惨案
前端·flutter
crasowas18 小时前
Flutter问题记录 - 适配Xcode 16和iOS 18
flutter·ios·xcode
老田低代码2 天前
Dart自从引入null check后写Flutter App总有一种难受的感觉
前端·flutter
AiFlutter2 天前
Flutter Web首次加载时添加动画
前端·flutter
ZemanZhang3 天前
Flutter启动无法运行热重载
flutter
AiFlutter4 天前
Flutter-底部选择弹窗(showModalBottomSheet)
flutter
帅次4 天前
Android Studio:驱动高效开发的全方位智能平台
android·ide·flutter·kotlin·gradle·android studio·android jetpack
程序者王大川4 天前
【前端】Flutter vs uni-app:性能对比分析
前端·flutter·uni-app·安卓·全栈·性能分析·原生
yang2952423614 天前
使用 Vue.js 将数据对象的值放入另一个数据对象中
前端·vue.js·flutter