flutter使用fishredux管理数据后自定义TabController
flutter小白踩坑记。
学习flutter,之前一直写的vue,也写过react,习惯于数据状态管理的flutter小白总想也找个flutter数据管理的插件做个数据统一管理,于是网上到处搜索了解,好乱啊,像vue就一个vuex直接用,方便非常(虽然也可以用redux)。找来找去,最后选了咸鱼团队的fishredux,一番折腾后,终于弄上去了,开森。可是接下来的问题一大堆,使用了fishredux管理数据后,很多写法都变了,心里再次迎来一万头马,mmp,坑来了!!!!最糟糕的是fishredux没有任何官方文档(反正我没找到)!!!
使用TabBarView后,TabController要怎么搞?
很明显以前的写法没法用了!
使用fishredux之前是这么写的
TabController mController;
Widget build(BuildContext context) {
@override
void initState() {
super.initState();
mController = TabController(
length: tabTitles.length,
vsync: this,
);
}
Widget _tabBarView() {
return TabBarView(
controller: mController,
children: tabTitles.map((item) {
return Container();
}).toList(),
);
}
}
用上了fishredux以后,这样写法直接报错啊,头大,一番折腾之后,终于找到了解决办法!
下面是我的部分目录结构,也是需要修改的部分
1.首先新建component.dart页面
component.dart页面代码如下
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/material.dart' hide Action;//注意这里
import 'state.dart';
class PersonListComponent extends ComponentState<PersonListState> with SingleTickerProviderStateMixin{
@override
PersonListComponent createState() => PersonListComponent();
}
注意这一行:import ‘package:flutter/material.dart’ hide Action;
后面的 hide Action,就是隐藏Action组件的意思,因为fishredux的Action和flutter本身的Action组件冲突了,这里将flutter本身的Action组件隐藏不引用。
然后再view.dart中声明tabbar切换的数据,即tab导航按钮数据
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/material.dart';
import 'tabBarComponents/AllPerson.dart';
import 'tabBarComponents/ToLoanPerson.dart';
import 'tabBarComponents/TransactionPerson.dart';
import 'tabBarComponents/WorkPerson.dart';
import 'tabBarComponents/ExitPerson.dart';
import 'action.dart';
import 'state.dart';
import 'package:labour_app/globalComponents/TopTabBar.dart';//我的TopTabBar是存放在globalComponents文件夹中
//tabList是tabbar切换的数据
List tabList = [
{
"title":'全部人员',
"widget":AllPerson(),
"index":0,
},
{
"title":'在场人员',
"widget":WorkPerson(),
"index":1,
},
{
"title":'退场人员',
"widget":ExitPerson(),
"index":2,
},
{
"title":'异动人员',
"widget":TransactionPerson(),
"index":3,
},
];
var personType=0;//人员类型
_renderPersonList(int index,List persons){
Widget buildView(PersonListState state, Dispatch dispatch, ViewService viewService) {
return MaterialApp(
theme: ThemeData(
brightness: Brightness.light,
primaryColor: Colors.white,
textTheme: TextTheme(
title: TextStyle(fontSize: 18.0,),
),
),
home: Scaffold(
backgroundColor: Color(0xFFf5f5f5),
appBar: AppBar(
title: Text('劳务人员'),
leading: GestureDetector(
onTap:(){
//顺便提一下,在view.dart里面可以在viewService中找到context,等下告诉你我是怎么找到的
Navigator.of(viewService.context).pop();
},
child: Icon(Icons.arrow_back_ios,color: Colors.grey,),
),
centerTitle: true,
),
body: Column(
children: <Widget>[
Container(
color: Color(0xffffffff),
height: 50.0,
//这里将tabBar组件提出去封装了
child: TopTabBar(tabList:tabList,controller:state.controller),
),
//TabBarView外层加上Expanded,不然会报错,具体报啥忘了,感兴趣的自己去试
Expanded(
child: TabBarView(
controller: state.controller,//这里从state中取出controller赋值给TabBarView的controller即可
children: tabList.map((item) {
return Container(
child:Text('页面')
);
}).toList(),
),
)
],
),
),
);
}
TopTabBar组件,我的TopTabBar是存放在globalComponents文件夹中
import 'package:flutter/material.dart';
class TopTabBar extends StatefulWidget {
@override
final List tabList;
final TabController controller;
TopTabBar({
Key key,
@required this.tabList,
@required this.controller
}):super(key:key);
@override
TopTabBarState createState() => TopTabBarState();
}
class TopTabBarState extends State<TopTabBar>{
@override
Widget build(BuildContext context) {
return TabBar(
isScrollable: true,
//是否可以滚动
controller: widget.controller,
labelColor: Color(0xff248bfe),
unselectedLabelColor: Color(0xff666666),
labelStyle: TextStyle(fontSize: 16.0),
tabs: widget.tabList.map((item) {
return Tab(
text: item["title"],
);
}).toList(),
onTap:(index){
print(index);
},
);
}
}
state.dart中
import 'dart:ui';
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/material.dart';
class PersonListState implements Cloneable<PersonListState>, GlobalBaseState{
PersonListState clone() {
return PersonListState();
}
@override
TabController controller;
@override
Color themeColor;
}
PersonListState initState(Map<String, dynamic> args) {
return PersonListState();
}
reducer.dart中
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/material.dart' hide Action;
import 'package:labour_app/views/PersonList/view.dart';
import 'action.dart';
import 'state.dart';
Reducer<PersonListState> buildReducer() {
return asReducer(
<Object, Reducer<PersonListState>>{
PersonListAction.changeTabListAction: _onInItController,
},
);
}
//初始化controller控制
PersonListState _onInItController(PersonListState state, Action action) {
TabController controller =action.payload["controller"] ?? null;
final PersonListState newState = state.clone();
newState.controller=controller;
return newState;
}
page.dart中
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/material.dart' hide Action;//这里注意,要隐藏Action类
import 'effect.dart';
import 'reducer.dart';
import 'state.dart';
import 'view.dart';
import 'component.dart';
class PersonListPage extends Page<PersonListState, Map<String, dynamic>> {
PersonListPage()
: super(
initState: initState,
effect: buildEffect(),
reducer: buildReducer(),
view: buildView,
dependencies: Dependencies<PersonListState>(
adapter: null,
slots: <String, Dependent<PersonListState>>{
}),
middleware: <Middleware<PersonListState>>[
],);
//这下面几行是创建component.dart后必须加的
@override
ComponentState<PersonListState> createState() {
return PersonListComponent();
}
}
effect.dart中
偷偷告诉你一个惊天秘密,在view.dart中声明的变量在effect.dart中可以看到哦!!我的天哪,还有这操作!!所以我在view.dart中声明的tabList数据变量可以在effect.dart中直接拿来使用!

再告诉你一个惊天发现,我是从这里判断到view.dart可以从viewService中取到context的,我们来分分析一下:
void _initController(Action action,Context ctx){
ctx.dispatch(PersonListActionCreator.onChangeTabListAction({tabList:tabList,‘controller’:_controller}));
}
从这里可以看到,effect中有ctx,而其他几个文件是没有的
然后再看看view.dart中
Widget buildView(PersonListState state, Dispatch dispatch, ViewService viewService) {})
按我web端的思想,要想取到context,最先想到的是this中,可是再这里直接写this报错,那么就只能从参数中尝试
Widget buildView总共三个参数。第一个state,不用猜就是state.dart里面的东西;第二个dispatch,用过 vuex 或者 redux 想必都很清楚,这是 action 的东西,何况这插件叫f ishredux ,那么就只剩下第三个viewService,看字面意思,不久视图服务嘛?而 context也是界面,果断试了下 viewService.context ,成功!!
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/material.dart' hide Action; //注意要隐藏Actio类
import 'package:flutter/widgets.dart' hide Action; //注意要隐藏Actio类
import 'package:labour_app/views/PersonList/view.dart';
import 'action.dart';
import 'state.dart';
Effect<PersonListState> buildEffect() {
return combineEffects(<Object, Effect<PersonListState>>{
Lifecycle.initController: _initController, //页面初始化监听tabbar控制
});
}
void _initController(Action action,Context<PersonListState> ctx){
final TickerProvider tickerProvider = ctx.stfState as TickerProvider;
var _controller =TabController(vsync: tickerProvider,length: tabList.length);
_controller.addListener((){
println(_controller.index);
});
ctx.dispatch(PersonListActionCreator.onChangeTabListAction({
tabList:tabList,'controller':_controller}));
}
action.dart中
import 'package:fish_redux/fish_redux.dart';
//TODO replace with your own action
enum PersonListAction {
changeTabListAction
}
//tabbar contruller
static Action onChangeTabListAction(params) {
/*
params是effect.dart中ctx.dispatch(PersonListActionCreator.onChangeTabListAction({tabList:tabList,'controller':_controller})); 传递来的参数,
即params就是{tabList:tabList,'controller':_controller}
action里通过payload接收
*/
return Action(PersonListAction.changeTabListAction,payload:params);
}]
}
好了,运行下试试,搞定!!!