1. 简介
fish_redux 是阿里咸鱼开源的flutter框架,用于页面拆分,模块拆分及跨组件通讯的,里面给ListView 提供了Adapter的功能,但是实现对于初学者来说很难理解。
阅读本文章需要掌握fish_redux的基本使用
新版本中框架提供了4中adapter
SourceFlowAdapter //Model数组类型驱动
StaticFlowAdapter //以Map数据类型驱动的
DynamicFlowAdapter//Model数组类型驱动 已被弃用,SourceFlowAdapter代替
CustomAdapter //自定义驱动
本文主要介绍 SourceFlowAdapter 的基础使用,进阶使用和原理等,不在此做介绍
2. 使用
-
先使用FishReduxTemplate 工具新建一个标准页面,文件目录如下
-
在user_view.dart 中,编写项目的布局,添加一个listview
Widget buildView(userState state, Dispatch dispatch, ViewService viewService) { //从viewService中取adapter,固定写法 final ListAdapter adapter = viewService.buildAdapter(); return Scaffold( appBar: AppBar( title: Text("用户"), centerTitle: true, ), body: Container( child: ListView.builder( itemCount: adapter.itemCount, itemBuilder: adapter.itemBuilder), )); ); }
-
在user下新建一个包,命名为item,使用FishReduxTemplate 工具新建一个Component,命名为UserItem,可以勾选action和reducer,也可以不勾选, 对于Component,此处可以理解为listview的item;
新建后的文件目录
-
新建一个User Model,就是ListView 展示数据的Model
class User { int type; String name; String introduction; User({this.type, this.name, this.introduction}); User.fromJson(Map<String, dynamic> json) { type = json['type']; name = json['name']; introduction = json['introduction']; } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); data['type'] = this.type; data['name'] = this.name; data['introduction'] = this.introduction; return data; } @override String toString() { return 'User{data:$name,introduction:$introduction}'; } }
-
修改user_item_state.dart文件,定义item 上需要展示的数据源
class UserItemState implements Cloneable<UserItemState> { //这个就是每个item需要显示的数据 User user; //构造方法 UserItemState({this.user}); @override UserItemState clone() { return UserItemState() ..user = user; } } UserItemState initState(Map<String, dynamic> args) { return UserItemState(); }
-
修改user_item_view.dart ,这个就是item的布局文件
Widget buildView(UserItemState state, Dispatch dispatch, ViewService viewService) { return Container( margin: EdgeInsets.fromLTRB(0, 0, 0, 10), height: 120.0, color: Colors.white, alignment: Alignment.center, child: GestureDetector( child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ //左侧图标 Container( padding: const EdgeInsets.only(right: 5.0), child: Icon( //不同type显示不同icon state.user.type == 1 ? Icons.account_circle : Icons.account_box, size: 50.0, ), ), //右侧 Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ //标题部分 Container( height: 30, child: Text( state.user.name, style: TextStyle(fontSize: 22.0), ), ), //内容部分 Text( state.user.introduction, style: TextStyle(fontSize: 16.0), ), ], ), ), ], ), onTap: () { //todo 点击事件 }, ), ); }
-
user_item_component.dart不需要修改,默认就可以;
-
在 user 下新建 adapter ,使用FishReduxTemplate新建一个SourceFlowAdapter,下方的action、state、view可以根据自己需要创建
-
修改adapter.dart
//泛型中修改为UserState,修改后会报错,别急,等下我们去改造UserState
class UserAdapterAdapter extends SourceFlowAdapter<UserState> {
//这个用来区分Component类型的,
//类似于Android recyclerView adapter 中的getItemViewType这个方法的功能
static const userType = 'user';
UserAdapterAdapter()
: super(
pool: <String, Component<Object>>{
userType: UserItemComponent()//刚刚创建的UserItemComponent
}
)
;
}
- 改造UserState,我们看到错误是没有继承AdapterSource,框架提供了AdapterSource 的两个子类,分别是可变数据源的 MutableSource 和不可变数据源的 ImmutableSource,此处我们用MutableSource;让UserState继承MutableSource,同时在UserState中定义ListView 的数据源;
!!!ListView的数据源,一定要是item的stateclass UserState extends MutableSource implements Cloneable<UserState> { //ListView的数据源,此处一定要是item的State List<UserItemState> userItemStateList; @override UserState clone() { return UserState() ..userItemStateList = userItemStateList; } @override Object getItemData(int index) { // TODO: implement getItemData // 对应 index 下的数据 return userItemStateList[index]; } @override String getItemType(int index) { // TODO: implement getItemType // 对应 index 下的数据类型,在Adapter里面定义的 return UserAdapterAdapter.userType; } @override // TODO: implement itemCount // 数据源长度 int get itemCount => userItemStateList?.length ?? 0; @override void setItemData(int index, Object data) { // TODO: implement setItemData userItemStateList[index] = data; } } UserState initState(Map<String, dynamic> args) { return UserState(); }
- 最后修改user_page.dart,关联adapter
- 修改user_effect.dart,在页面初始化的时候,模拟网络请求,拿到ListView的数据
Effect<UserState> buildEffect() { return combineEffects(<Object, Effect<UserState>>{ Lifecycle.initState: _init, //页面一加载就会执行此方法 }); } void _init(Action action, Context<UserState> ctx) { //模拟获取数据 List<User> userList = List(); userList.add(User() ..type = 1 ..name = "11111" ..introduction = "11111"); userList.add(User() ..type = 2 ..name = "22222" ..introduction = "22222"); userList.add(User() ..type = 3 ..name = "333333" ..introduction = "333333"); userList.add(User() ..type = 4 ..name = "444444" ..introduction = "444444"); ///构建符合要求的列表数据源 List<UserItemState> items = List.generate(userList.length, (index) { return UserItemState(user: userList[index]); }); //发送更新view的消息 ctx.dispatch(UserActionCreator.onSetListData(items)); }
- 接下来就是在user_reducer.dart 中刷新页面了
Reducer<UserState> buildReducer() { return asReducer( <Object, Reducer<UserState>>{ UserAction.setListData: _onSetListData, }, ); } //刷新ListView 页面 UserState _onSetListData(UserState state, Action action) { final UserState newState = state.clone(); newState.userItemStateList = action.payload; return newState; }
- 最后,我们运行来看看,一个简单的ListView页面就完成啦
Demo 代码地址 https://github.com/chxip/fish_redux_listview.