GetX Plus
精简、轻量的 GetX 维护分支 — 聚焦状态管理、依赖注入、路由导航三大核心,去除非必要模块,保持简洁可控。
A lightweight maintained fork of GetX. Keeps the core trio — state management, dependency injection, and navigation — while removing GetConnect, custom i18n, GetUtils, animations, and Navigator 2.0 Router API.
与原始 GetX 的关系
| 原始 GetX | GetX Plus 5.0 | |
|---|---|---|
| 上游仓库 | jonataslaw/getx | Matkurban/getx_plus |
| 基线版本 | 5.0.0-release-candidate | 基于上游 RC 精简 |
| 定位 | 大而全的框架 | 仅保留核心三大功能 |
| 国际化 | 自定义 Translations + .tr |
已移除,使用 Flutter 原生 intl |
| HTTP 客户端 | GetConnect |
已移除,使用 dio / http |
| 工具扩展 | GetUtils(校验、格式化等) |
已移除 |
| 动画 | GetAnimations 模块 |
已移除 |
已删除的功能
升级到 5.0 时请注意,以下功能已被完全移除:
| 已删除功能 | 说明 | 替代方案 |
|---|---|---|
| GetConnect | HTTP 客户端、WebSocket、GraphQL | dio、http、web_socket_channel |
| 国际化 (i18n) | Translations、.tr、Get.locale |
Flutter Localizations + intl 包 |
| GetUtils | 字符串校验、Widget 扩展、num 延时等 | 自行编写或使用社区包 |
| GetAnimations | 预封装动画组件 | Flutter 原生 AnimatedBuilder 等 |
| Navigator 2.0 Router API | GetDelegate、GetRouterOutlet、RouteDecoder、ParseRouteTree |
使用保留的 Navigator 1.0 命名路由 |
| go_router | 外部路由依赖 | 使用内置 GetPage 路由 |
| GetCommon | GetReset 等 |
— |
保留的功能
状态管理
完整的响应式与手动刷新体系:
响应式变量 (Rx)
final count = 0.obs; // RxInt
final name = ''.obs; // RxString
final user = Rxn<User>(); // Rx<User?>(可空)
final list = <String>[].obs; // RxList
final map = <String, int>{}.obs; // RxMap
final set = <int>{}.obs; // RxSet
状态管理组件
| 组件 | 类型 | 说明 |
|---|---|---|
Obx(() => ...) |
响应式 | 自动监听 .obs 变量并刷新 |
ObxValue<T>(builder, data) |
响应式 | 管理局部 Rx 状态 |
GetX<T>(builder: ...) |
响应式 | 完整生命周期的响应式组件 |
GetBuilder<T>(builder: ...) |
手动 | 通过 controller.update() 刷新 |
MixinBuilder<T> |
混合 | 结合 GetBuilder + Obx |
ValueBuilder<T> |
回调 | 无需控制器的局部状态 |
控制器
| 类 | 说明 |
|---|---|
GetxController |
标准控制器,带 update() 手动刷新 |
RxController |
轻量控制器,仅用于 Rx |
GetxService |
永久实例,不会被自动回收(适合 AuthService 等) |
便捷视图
| 类 | 说明 |
|---|---|
GetView<T> |
自动注入控制器,通过 controller getter 直接可用 |
GetWidget<S> |
类似 GetView,配合 Get.create() 使用 |
GetResponsiveView<T> |
响应式布局,按设备类型切换 UI |
GetResponsiveWidget<T> |
响应式布局(继承 GetWidget) |
Workers(变化监听器)
ever(count, (val) => print('changed: $val')); // 每次变化
once(count, (val) => print('first: $val')); // 仅触发一次
debounce(count, (val) => search(val), time: 500.ms); // 防抖
interval(count, (val) => save(val), time: 1.seconds); // 节流
everAll([a, b], (val) => print('any changed')); // 监听多个
异步状态 (StateMixin)
class MyController extends GetxController with StateMixin<List<User>> {
void fetchUsers() {
change(null, status: GetStatus.loading());
repo.getUsers().then((data) {
change(data, status: GetStatus.success());
}).catchError((e) {
change(null, status: GetStatus.error('加载失败'));
});
}
}
// 视图中使用
controller.obx(
(data) => ListView(...),
onLoading: CircularProgressIndicator(),
onError: (e) => Text(e!),
onEmpty: Text('暂无数据'),
);
AnimationController 支持
class MyController extends GetxController with GetTickerProviderStateMixin {
late AnimationController anim;
@override
void onInit() {
super.onInit();
anim = AnimationController(vsync: this, duration: 300.ms);
}
}
// 也可使用 SingleGetTickerProviderMixin(仅支持单个 Ticker)
依赖注入
// ── 注册 ──
Get.put(CounterController()); // 立即注册单例
Get.lazyPut(() => ApiService()); // 懒加载,首次 find 时创建
Get.lazyPut(() => ApiService(), fenix: true); // fenix: 被删后可重建
Get.create(() => TempController()); // 每次 find 返回新实例
// ── 获取 ──
final ctrl = Get.find<CounterController>();
final ctrl = Get<CounterController>(); // 简写
// ── 查询与清理 ──
Get.isRegistered<CounterController>(); // → bool
Get.delete<CounterController>(); // 从内存移除
Get.getInstanceInfo<CounterController>(); // → InstanceInfo
Get.resetInstance(); // 清除全部(测试用)
// ── Bindings(配合路由使用)──
class HomeBinding implements Bindings {
@override
List<Bind> dependencies() => [
Bind.put(HomeController()),
Bind.lazyPut(() => AnalyticsService()),
];
}
GetPage(name: '/home', page: () => HomePage(), binding: HomeBinding());
SmartManagement 模式
| 模式 | 说明 |
|---|---|
SmartManagement.full(默认) |
路由关闭时自动回收未使用的控制器 |
SmartManagement.keepFactory |
回收实例但保留工厂,可重新创建 |
SmartManagement.onlyBuilder |
仅回收通过 GetBuilder/GetX 创建的控制器 |
路由导航
基础用法 — 无需 BuildContext
// ── Widget 跳转 ──
Get.to(() => DetailPage()); // push
Get.off(() => LoginPage()); // 替换当前页
Get.offAll(() => HomePage()); // 清空栈并跳转
Get.offUntil(() => HomePage(), (route) => false); // pop 到条件满足,再 push
// ── 命名路由 ──
Get.toNamed('/detail');
Get.toNamed('/detail', arguments: {'id': 42});
Get.toNamed('/search', parameters: {'q': 'flutter'}); // → /search?q=flutter
Get.offNamed('/login');
Get.offAllNamed('/home');
Get.offNamedUntil('/home', (route) => false);
Get.offAndToNamed('/dashboard');
// ── 栈操作 ──
Get.replaceRoute(() => NewPage(), oldRoute: route); // 替换栈中指定路由
Get.replaceRouteBelow(() => NewPage(), anchorRoute: r); // 替换锚点路由下方的路由
Get.removeRoute(route); // 移除栈中指定路由
Get.removeRouteBelow(anchorRoute); // 移除锚点路由下方的路由
Get.restorablePush(routeBuilder); // 推入可恢复的路由
// ── 返回 ──
Get.back();
Get.back(result: 'done');
Get.back(times: 2); // 连续返回 2 层
Get.until((route) => route.settings.name == '/home'); // pop 到指定路由
// ── 路由信息 ──
Get.currentRoute // 当前路由名
Get.previousRoute // 上一个路由名
Get.arguments // 路由参数
Get.parameters // URI 路径参数 + 查询参数
路由定义
GetMaterialApp(
initialRoute: '/',
unknownRoute: GetPage(name: '/404', page: () => NotFoundPage()),
defaultTransition: Transition.rightToLeft,
getPages: [
GetPage(name: '/', page: () => HomePage()),
GetPage(
name: '/detail/:id',
page: () => DetailPage(),
binding: DetailBinding(),
transition: Transition.fade,
middlewares: [AuthMiddleware()],
),
// 嵌套路由 — children 会自动展开
GetPage(
name: '/settings',
page: () => SettingsPage(),
children: [
GetPage(name: '/profile', page: () => ProfilePage()), // → /settings/profile
GetPage(name: '/theme', page: () => ThemePage()), // → /settings/theme
],
),
],
);
动态路由参数
// 路由定义
GetPage(name: '/user/:id', page: () => UserPage());
GetPage(name: '/post/:id/:slug', page: () => PostPage());
// 导航
Get.toNamed('/user/123');
Get.toNamed('/post/42/hello-world?tab=comments');
// 读取参数
Get.parameters['id'] // '123'
Get.parameters['slug'] // 'hello-world'
Get.parameters['tab'] // 'comments'
路由中间件
class AuthMiddleware extends GetMiddleware {
@override
int? get priority => 1; // 数值越小越先执行
@override
RouteSettings? redirect(String? route) {
if (!isLoggedIn) return const RouteSettings(name: '/login');
return null; // 不重定向,正常继续
}
@override
GetPage? onPageCalled(GetPage? page) => page;
@override
List<Bindings>? onBindingsStart(List<Bindings>? bindings) => bindings;
@override
GetPageBuilder? onPageBuildStart(GetPageBuilder? page) => page;
@override
Widget onPageBuilt(Widget page) => page;
@override
void onPageDispose() {}
}
转场动画(16 种)
| 动画 | 说明 |
|---|---|
Transition.fade |
淡入淡出 |
Transition.fadeIn |
淡入 |
Transition.rightToLeft |
从右向左滑入 |
Transition.leftToRight |
从左向右滑入 |
Transition.upToDown |
从上向下滑入 |
Transition.downToUp |
从下向上滑入 |
Transition.rightToLeftWithFade |
右向左 + 淡入 |
Transition.leftToRightWithFade |
左向右 + 淡入 |
Transition.zoom |
缩放 |
Transition.topLevel |
顶层覆盖 |
Transition.noTransition |
无动画 |
Transition.cupertino |
iOS 风格 |
Transition.cupertinoDialog |
iOS 对话框风格 |
Transition.size |
尺寸变换 |
Transition.circularReveal |
圆形揭示 |
Transition.native |
平台默认 |
也支持 CustomTransition 自定义动画。
GetCupertinoApp — iOS 风格应用入口,参数与 GetMaterialApp 一致。
其他保留功能
| 功能 | 说明 |
|---|---|
Get.changeTheme(ThemeData) |
运行时切换主题 |
Get.changeThemeMode(ThemeMode) |
切换亮色/暗色模式 |
Get.appUpdate() |
触发根组件重建 |
Get.log(msg) |
日志输出(可自定义 logWriterCallback) |
ScrollMixin |
在控制器中监听滚动到顶部/底部 |
GetTickerProviderStateMixin |
在控制器中使用 AnimationController |
SingleGetTickerProviderMixin |
单 Ticker 版本 |
routingCallback |
全局路由变化回调 |
安装
dependencies:
getx_plus: ^5.0.0
import 'package:getx_plus/get.dart';
环境要求:Dart ^3.10.0 / Flutter ^3.38.1
快速示例
import 'package:flutter/material.dart';
import 'package:getx_plus/get.dart';
void main() => runApp(
GetMaterialApp(
initialRoute: '/',
getPages: [
GetPage(name: '/', page: () => const HomePage()),
GetPage(name: '/detail', page: () => const DetailPage()),
],
),
);
// ── 控制器 ──
class CounterController extends GetxController {
final count = 0.obs;
void increment() => count++;
}
// ── 首页 ──
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
final c = Get.put(CounterController());
return Scaffold(
appBar: AppBar(title: Obx(() => Text('点击: ${c.count}'))),
body: Center(
child: ElevatedButton(
onPressed: () => Get.toNamed('/detail'),
child: const Text('前往详情'),
),
),
floatingActionButton: FloatingActionButton(
onPressed: c.increment,
child: const Icon(Icons.add),
),
);
}
}
// ── 详情页 ──
class DetailPage extends StatelessWidget {
const DetailPage({super.key});
@override
Widget build(BuildContext context) {
final c = Get.find<CounterController>();
return Scaffold(
appBar: AppBar(title: const Text('详情')),
body: Center(child: Obx(() => Text('总计: ${c.count}'))),
);
}
}
速查表
| 场景 | 调用 |
|---|---|
| 跳转页面 | Get.to(() => Page()) |
| 命名路由跳转 | Get.toNamed('/page') |
| 替换当前页 | Get.off(() => Page()) |
| 清空栈并跳转 | Get.offAll(() => Page()) |
| 替换栈中路由 | Get.replaceRoute(() => Page(), oldRoute: r) |
| 移除栈中路由 | Get.removeRoute(route) |
| 返回 | Get.back() |
| 注入依赖 | Get.put(Controller()) |
| 懒加载注入 | Get.lazyPut(() => Controller()) |
| 获取依赖 | Get.find<Controller>() |
| 响应式变量 | final x = 0.obs |
| 响应式刷新 | Obx(() => Text('$x')) |
| 手动刷新 | GetBuilder<T>(builder: ...) + update() |
| 路由参数 | Get.parameters['key'] |
| 传递参数 | Get.toNamed('/page', arguments: data) |
| 当前路由 | Get.currentRoute |
从原始 GetX 迁移
如果你从原始 GetX 或 getx_plus 4.x 升级:
- 移除
GetConnect用法 — 替换为dio或http - 移除
.tr国际化 — 替换为 Flutterintl+Localizations - 移除
GetUtils调用 — 替换为自有工具或社区包 - 移除 Router API 用法 —
GetDelegate、GetRouterOutlet等不再存在,改用GetPage+ 命名路由 Binding→Bindings— 如果使用了旧的Binding基类,改用Bindings接口- 移除
go_router— 不再需要外部路由依赖
详细文档
本地文档目录(与原项目结构一致):
- 状态管理:
documentation/en_US/state_management.md - 路由管理:
documentation/en_US/route_management.md - 依赖管理:
documentation/en_US/dependency_management.md
中文文档:documentation/zh_CN/ 下同名文件。
参与贡献
欢迎 Issue 和 PR:
- 保持代码风格一致
- 保持向后兼容;破坏性变更请先开 Issue 讨论
- 提交时附带最小化测试
License
沿用原项目 MIT License。
致谢
感谢 jonataslaw 及 GetX 社区贡献者的原始工作。
Libraries
- getx_plus
- GetX is an extra-light and powerful multi-platform framework. It combines high performance state management, intelligent dependency injection, and route management in a quick and practical way.