项目中使用 GetX,使用 GetX 依赖注入。创建 ShowToastBinding 类,并绑定ShowToastController。
class ShowToastBinding implements Bindings {
@override
void dependencies() {
Get.lazyPut(
() => ShowToastController(
),
);
}
}
在GetPage我添加了这个绑定,比如:
class Routes{
static const String SHOWTOAST="/ShowToast";
static final pages = [
GetPage(
name: Routes.SHOWTOAST,
page: () => ShowToastWidget(),
binding: ShowToastBinding(),
)
];
}
新建ShowToastController类继承GetxController,并添加一个普通函数showToastView()
class ShowToastController extends GetxController
void showToastView() {
}
}
新建HomeController,对TabController进行初始化操作,也贴下代码:
class HomeController extends GetxController with GetSingleTickerProviderStateMixin {
TabController? tabController;
@override
void onInit() {
super.onInit();
///添加监听器
tabController =
TabController(initialIndex: 0, vsync: this, length:2);
}
}
现在主界面如下:
class TabPage extends GetView {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: TabBar(
controller: controller.tabController,
tabs: [
Tab( child: Text("one",),),
Tab( child: Text("two",),
),
],
),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: TabBarView(
controller: controller.tabController,
physics: const NeverScrollableScrollPhysics(),
children: [
Center(
child: Container(
width: 200,
height: 50,
color: Colors.red,
),
),
ShowToastWidget(),
],
),
),
);
}
}
添加2个tab按钮 名字分别为one 和two one对应的界面是一个居中的红色背景的Container,two对应的是我们新增的布局 ShowToastWidget.同样TabPage 和ShowToastWidget去添加GetX依赖注入,如下
static const String tab_page="/tabpage";
static final pages = [
GetPage(
name: Routes.tab_page,
page: () => TabPage(),
binding:TabPageBinding()),
];
再来看下ShowToastWidget界面:
class ShowToastWidget extends GetView {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
width: 200,
height: 50,
child: ElevatedButton(
onPressed: () {
controller.showToastView();
},
child: Text("showToast"),
),
)),
);
}
}
继承getX框架中的GetView布局,并引入ShowToastController 这样就可以在当前布局调用ShowToastController里面的函数了。显示一个居中按钮 点击调用ShowToastController里的showToastView方法。
最后看下程序入口mian.dart
Future main() async {
runApp( HomeWidget());
}
class HomeWidget extends StatefulWidget {
@override
_HomeWidgetState createState() => _HomeWidgetState();
}
class _HomeWidgetState extends State {
@override
Widget build(BuildContext context) {
return GetMaterialApp(
getPages: Routes.pages,
initialBinding: TabPageBinding(),
home: Scaffold(
body: Center(
child: Container(
child: ElevatedButton(
onPressed: () {
Get.toNamed(Routes.tab_page);
},
child: Text("点击"),
),
),
),
),
);
}
}
使用GetX需要把MaterialApp改成GetMaterialApp才能使用,getPages去获取我们路由跳转的界面,initialBinding 我们就用TabPageBinding吧。
ok,现在整个界面应该是这样的:
程序运行 进入首界面,中间显示一个 ”点击“的按钮,然后点击按钮跳转到 有2个tab的TabView界面, 名为one的tab 界面下显示一个红色长方形的布局,点击名为two的tab 对应下面显示一个 名为”showToast"的居中按钮。
1、点击第一个界面的点击按钮
2、然后点击名为 two的tab标签
3、点击 showToast的按钮
4、查看日志
日志信息如下:
The following message was thrown while handling a gesture:
"ShowToastController" not found. You need to call "Get.put(ShowToastController())" or "Get.lazyPut(()=>ShowToastController())"
When the exception was thrown, this was the stack:
#0 GetInstance.find (package:get/get_instance/src/get_instance.dart:305:7)
#1 GetView.controller (package:get/get_state_manager/src/simple/get_view.dart:38:37)
#2 ShowToastWidget.build.
(package:flutter_test_demo/get/AddPage.dart:21:13) #3 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:989:21)
#4 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
...
显而易见,日志显示是GetX的Controller找不到。但我们确实依赖注入了呀。
GetPage(
name: Routes.SHOWTOAST,
page: () => ShowToastWidget(),
binding: ShowToastBinding(),
)
这时候我们突然也想到了 TabPage的注入方式和我们的ShowToastWidget 一毛一样的,为啥进入TabPage的时候,没有报这个错误?
细心的你们肯定发现了区别。TabPage 是在HomeWidget界面通过Get.toNamed(Routes.tab_page)跳转进入的,而 ShowToastWidget界面是通过tab点击进入的。
所以问题就是:跳转到ShowToastWidget界面没有使用 GetX 导航系统。是从同一页面切换选项卡。因此,ShowToastBinding该类对其没有影响。
Get.toNamed(Routes.SHOWTOAST)仅当您使用或导航时它才会生效Get.to(()=>ShowToastWidget(), binding: ShowToastBinding()),或者使用 Get.toNamed(Routes.SHOWTOAST)且 GetPage(
name: Routes.SHOWTOAST,
page: () => ShowToastWidget(),
binding: ShowToastBinding(),
);
除了tab 切换会导致这个问题,只要我们未使用GetX的路由跳转都会出现这个问题,比如我们在one tab界面下新增个按钮,用原生的代码去实现界面的跳转也会出现同样的问题:
TabBarView(
controller: controller.tabController,
physics: const NeverScrollableScrollPhysics(),
children: [
Center(
child: Container(
width: 200,
height: 50,
child: ElevatedButton(onPressed: (){
Navigator.push(context,
MaterialPageRoute(builder: (context) => ShowToastWidget()));
},child: Text("跳转"),),
),
),
ShowToastWidget(),
],
)
第一种就是采用 GetX的界面路由跳转方案。Get.to(()=>ShowToastWidget(), binding: ShowToastBinding())或使用 Get.toNamed(Routes.SHOWTOAST)且 GetPage(
name: Routes.SHOWTOAST,
page: () => ShowToastWidget(),
binding: ShowToastBinding(),
);
第二种就是像tab标签切换这种,把ShowToastBinding的依赖添加到TabPageBinding里,看如下操作:
GetPage(
name: Routes.tab_page,
page: () => TabPage(),
bindings:[ TabPageBinding(),ShowToastBinding()]),
在添加TabPage的getX依赖注入时,bindings里添加ShowToastBinding的绑定。这样修改后,继续走下上面问题复现的步骤,会发现问题不再复现了。