天天看点

Flutter fish_redux 框架 SourceFlowAdapter的使用

1. 简介

fish_redux 是阿里咸鱼开源的flutter框架,用于页面拆分,模块拆分及跨组件通讯的,里面给ListView 提供了Adapter的功能,但是实现对于初学者来说很难理解。

阅读本文章需要掌握fish_redux的基本使用

新版本中框架提供了4中adapter

SourceFlowAdapter //Model数组类型驱动
StaticFlowAdapter //以Map数据类型驱动的
DynamicFlowAdapter//Model数组类型驱动 已被弃用,SourceFlowAdapter代替
CustomAdapter //自定义驱动
           

本文主要介绍 SourceFlowAdapter 的基础使用,进阶使用和原理等,不在此做介绍

2. 使用

  1. 先使用FishReduxTemplate 工具新建一个标准页面,文件目录如下
    Flutter fish_redux 框架 SourceFlowAdapter的使用
  2. 在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),
          ));
      	);
    }
               
  3. 在user下新建一个包,命名为item,使用FishReduxTemplate 工具新建一个Component,命名为UserItem,可以勾选action和reducer,也可以不勾选, 对于Component,此处可以理解为listview的item;
    Flutter fish_redux 框架 SourceFlowAdapter的使用
    新建后的文件目录
    Flutter fish_redux 框架 SourceFlowAdapter的使用
  4. 新建一个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}';
      }
    }
               
  5. 修改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();
    	} 
               
  6. 修改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 点击事件
    
          },
        ),
      );
    } 
               
  7. user_item_component.dart不需要修改,默认就可以;
  8. 在 user 下新建 adapter ,使用FishReduxTemplate新建一个SourceFlowAdapter,下方的action、state、view可以根据自己需要创建
    Flutter fish_redux 框架 SourceFlowAdapter的使用
  9. 修改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
      }
  )
  ;
}
           
  1. 改造UserState,我们看到错误是没有继承AdapterSource,框架提供了AdapterSource 的两个子类,分别是可变数据源的 MutableSource 和不可变数据源的 ImmutableSource,此处我们用MutableSource;让UserState继承MutableSource,同时在UserState中定义ListView 的数据源;

    !!!ListView的数据源,一定要是item的state

    class 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();
    }
               
  2. 最后修改user_page.dart,关联adapter
    Flutter fish_redux 框架 SourceFlowAdapter的使用
  3. 修改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));
    }
               
  4. 接下来就是在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;
    }
               
  5. 最后,我们运行来看看,一个简单的ListView页面就完成啦
    Flutter fish_redux 框架 SourceFlowAdapter的使用

Demo 代码地址 https://github.com/chxip/fish_redux_listview.