可以看到Checkbox的内部点击操作,我们传递了一个id参数,注意这个id参数是必须的,在更新item的时候来做区分用的
Widget buildView(ItemState state, Dispatch dispatch, ViewService viewService) { return Container( child: InkWell( onTap: () {}, child: ListTile( title: Text(state.title), trailing: Checkbox( value: state.itemStatus, ///Checkbox的点击操作:状态变更 onChanged: (value) => dispatch(ItemActionCreator.onChange(state.id)), ), ), ), ); }action
一个状态改变的事件
enum ItemAction { onChange } class ItemActionCreator { //状态改变 static Action onChange(int id) { return Action(ItemAction.onChange, payload: id); } }reducer
_onChange会回调所有ItemState,所以这地方必须用id或其它唯一标识去界定,我们所操作的item具体是哪一个
_onChange方法,未操作的item返回的时候要注意,需要返回:state原对象,标明该state对象未变动,其item不需要刷新;不能返回state.clone(),这样返回的就是个全新的state对象,每个item都会刷新,还会造成一个很奇怪的bug,会造成后续点击item操作失灵
Reducer<ItemState> buildReducer() { return asReducer( <Object, Reducer<ItemState>>{ ItemAction.onChange: _onChange, }, ); } ItemState _onChange(ItemState state, Action action) { if (state.id == action.payload) { return state.clone()..itemStatus = !state.itemStatus; } ///这地方一定要注意,要返回:state;不能返回:state.clone(),否则会造成后续更新失灵 return state; } 多样式列表注意:如果使用多样式,items的列表泛型不要写成ItemState,写成Object就行了;在下面代码,我们可以看到,实现的getItemData()方法返回的类型是Object,所以Items的列表泛型写成Object,是完全可以的。
我们定义数据源的时候把泛型写成Object是完全可以的,但是初始化数据的时候一定要注意,写成对应adapter类型里面的state
假设一种情况,在index是奇数时展示:OneComponent;在index是奇数时展示:TwoComponent;
getItemType:这个重写方法里面,在index为奇偶数时分别返回:OneComponent和TwoComponent的标识
数据赋值时也一定要在index为奇偶数时赋值泛型分别为:OneState和TwoState
也可以这样优化去做,在getItemType里面判断当前泛型是什么数据类型,然后再返回对应的XxxxComponent的标识
数据源的数据类型必须和getItemType返回的XxxxComponent的标识相对应,如果数据源搞成Object类型,映射到对应位置的item数据时,会报类型不适配的错误
下述代码可做思路参考
class ListState extends MutableSource implements Cloneable<PackageCardState> { List<Object> items; @override ListState clone() { return PackageCardState()..items = items; } @override Object getItemData(int index) => items[index]; @override String getItemType(int index) { if(items[index] is OneState) { return PackageCardAdapter.itemStyleOne; }else{ return PackageCardAdapter.itemStyleTwo; } } @override int get itemCount => items.length; @override void setItemData(int index, Object data) => items[index] = data; } 列表存在的问题+解决方案 列表多item刷新问题这里搞定了单item刷新场景,还存在一种多item刷新的场景
说明下,列表item是没办法一次刷新多个item的,只能一次刷新一个item(一个clone对应着一次刷新),一个事件对应着刷新一个item;这边是打印多个日志分析出来了
解决:解决办法是,多个事件去处理刷新操作
举例:假设一种场景,对于上面的item只能单选,一个item项被选中,其它item状态被重置到未选状态,具体效果看下方效果图
效果图
这种效果的实现非常简单,但是如果思路不对,会掉进坑里出不来
还原被选的状态,不能在同一个事件里写,需要新写一个清除事件
下述代码为整体流程
view
Widget buildView(ItemState state, Dispatch dispatch, ViewService viewService) { return InkWell( onTap: () {}, child: ListTile( title: Text(state.title), trailing: Checkbox( value: state.itemStatus, ///CheckBox的点击操作:状态变更 onChanged: (value) { //单选模式,清除选中的item,以便做单选 dispatch(ItemActionCreator.clear()); //刷新选中item dispatch(ItemActionCreator.onChange(state.id)); } ), ), ); }