0%

RecyclerView常用封装

RecyclerView常用的一种封装方式

本文介绍一种RecyclerView的常用封装形式,最后效果是调用时只需定义回调方法getItemViewType()与onCreateViewHolder(View, int)
因为在使用时一般会有特殊的item填充的需求,以及不同使用场景会使用不同的ViewHolder进行填充的需求。
先上代码…

具体代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder<T>> implements View.OnClickListener, AdapterCallBack<T> {
private final List<T> list;

private AdapterListener<T> mListener;

/**
* 构造模块
* ------------------------------------------------------------------
*
* @param dataList
* @param listener
*/
public RecyclerAdapter(List<T> dataList, AdapterListener<T> listener) {
this.mListener = listener;
this.list = dataList;
}

public RecyclerAdapter() {
this(null);
}

public RecyclerAdapter(AdapterListener<T> listener) {
this(new ArrayList<T>(), listener);
}

/**
* ViewId获取模块
* ------------------------------------------------------------------
* 复写默认布局返回
*
* @param position 坐标
* @return 返回布局id
*/
@Override
public int getItemViewType(int position) {
return getItemViewType(position, list.get(position));
}

/**
* 获取布局类型(id)
*
* @param position 坐标
* @param data 当前数据
* @return 布局id,用于创建ViewHolder
*/
protected abstract int getItemViewType(int position, T data);

/**
* ViewHolder创建模块
* ------------------------------------------------------------------
* 创建一个ViewHolder
*
* @param parent
* @param viewType Item的类型,约定为XML的id(简化操作)
* @return ViewHolder
*/
@Override
public ViewHolder<T> onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());

// 将一个xml id为ViewType的文件初始化为一个root View
View root = inflater.inflate(viewType, parent, false);
// 通过子类必须实现的方法得到一个ViewHolder
ViewHolder<T> holder = onCreateViewHolder(root, viewType);
// 对Holder的事件操作实际上是对view进行操作。对一个ViewHolder设置事件实际上还是对其根布局设置

//设置View的Tag为Holder进行双向绑定
root.setTag(R.id.tag_recycler_holder, holder);
// 设置事件点击
root.setOnClickListener(this);

// 进行界面注解绑定
holder.unBinder = ButterKnife.bind(holder, root);

// 绑定callback
holder.callBack = this;
return holder;
}

/**
* 当得到一个新的ViewHolder
*
* @param parent 根布局
* @param viewType 布局类型,即xml的id
* @return ViewHolder
*/
public abstract ViewHolder<T> onCreateViewHolder(View parent, int viewType);

/**
* Holder数据绑定模块
* ------------------------------------------------------------------
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(ViewHolder<T> holder, int position) {
// 得到需要绑定的方法
T data = list.get(position);
// 触发Holder的绑定方法
holder.bind(data);
}

@Override
public int getItemCount() {
return list.size();
}


/**
* 操作数据列表模块
* ------------------------------------------------------------------
*/
private void add(T data) {
list.add(data);
notifyItemInserted(list.size() - 1);
}

/**
* 插入一堆数据并通知这段集合更新
*
* @param datalist data
*/
public void add(T... datalist) {
if (datalist != null && datalist.length > 0) {
int startPos = list.size();
Collections.addAll(list, datalist);
notifyItemRangeInserted(startPos, datalist.length);
}
}

/**
* 插入一堆数据并通知这段集合更新
*
* @param datalist data
*/
public void add(Collection<T> datalist) {
if (datalist != null && datalist.size() > 0) {
int startPos = list.size();
list.addAll(datalist);
notifyItemRangeInserted(startPos, datalist.size());
}
}

/**
* 删除操作
*/
public void clear() {
list.clear();
notifyDataSetChanged();
}

/**
* 替换为一个新的集合
*
* @param dataList 新集合
*/
public void replace(Collection<T> dataList) {
list.clear();
if (dataList == null || dataList.size() == 0)
return;
list.addAll(dataList);
// 全部更新
notifyDataSetChanged();
}


/**
* 点击设置及监听模块
* ------------------------------------------------------------------
*/
@Override
public void onClick(View v) {
ViewHolder holder = (ViewHolder) v.getTag(R.id.tag_recycler_holder);
if (this.mListener != null) {
// 得到ViewHolder当前对应适配器中的坐标
int pos = holder.getAdapterPosition();
// 回调
this.mListener.onItemClick(holder, list.get(pos));
}
}

/**
* 设置适配器点击监听
*
* @param adapterListener
*/
public void setListener(AdapterListener<T> adapterListener) {
this.mListener = adapterListener;
}

public interface AdapterListener<T> {
// 当cell点击时触发
void onItemClick(RecyclerAdapter.ViewHolder holder, T data);

void onItemLongClick(RecyclerAdapter.ViewHolder holder, T data);
}

/**
* 加上abstract使子类实现时至少实现其中一个方法
* 抽象方法不需要子类实现所有抽象方法,而接口要求实现所有方法
*/
public abstract static class AdapterListenerImpl<T> implements AdapterListener<T> {
@Override
public void onItemClick(ViewHolder holder, T data) {}

@Override
public void onItemLongClick(ViewHolder holder, T data) {}
}

/**
* ViewHolder的封装类
* 使用时需继承该类并实现onBind()方法完成控件与数据的绑定
* ------------------------------------------------------------------
*/
public static abstract class ViewHolder<T> extends RecyclerView.ViewHolder {
private Unbinder unBinder;

private AdapterCallBack<T> callBack;
protected T data;

public ViewHolder(View v) {
super(v);
}

/**
* 用于绑定数据的触发
* @param data 数据
*/
void bind(T data) {
this.data = data;
onBind(data);
}

/**
* 通知整个列表更新的消息
* 通过ViewHolder反向调用此方法进行更新
* Holder自己对自己对应的data进行更新的
*
* @param data
*/
public void updataData(T data) {
if (this.callBack != null) {
this.callBack.updata(data, this);
}
}

/**
* 触发帮顶数据时的回调。必须复写
* 界面刷新赋值
* @param data 绑定的数据
*/
protected abstract void onBind(T data);
}
}

以上代码看着有点多,因此分为几个模块,分开理解就都很简单了。

代码分析

其实注释已经写得很清楚了但还是具体分析一下。

构造模块

  • 传入AdapterListener监听器实例

ViewType模块

  • getItemViewType() 复写默认布局返回,布局id用于创建ViewHolder,返回调用同名抽象方法(不同参)

创建ViewHolder模块

  • onCreateViewHolder 创建一个ViewHolder
    • 调用类内定义的同名抽象方法onCreateViewHolder()获取holder,参数为View而不是ViewGroup
    • View与Holder进行双向绑定(两种实现方式)
      • view.setTag()实现(key为一个特定id)
      • Butterknife.bind()实现,并将返回的UnBinder保存在Holder中备用

数据绑定模块

  • onBindViewHolder
    • 触发 Holder.bind() 方法(有点会回调的意思)

点击响应以及监听模块

  • AdapterListener 点击监听接口
    • 由onClick()方法回调接口方法
    • 增加一个接口实现类,就可以只实现接口中的其中一个方法,而不需要全部实现

ViewHolder抽象类模块

  • ViewHolder 内部类定义
    • 以前的写法是在构造方法中绑定控件,但是这里是定义了一个bind(T)进行绑定
      • bind()中调用abstract onBind()方法
    • 需要通知整个列表更新的消息,定义方法updataData()
      • updataData方法回调了AdapterCallBack(外部定义)。

数据操作模块

  • add() & clear() & replace() & 以及必须实现的 getItemCount()
    • 对数据源进行修改,注意刷新列表更新

对RecyclerView使用的一种常用封装,为了开发是能够便捷简明的调用而又不影响其复用。

以上是对这种封装形式的学习理解和分析,理解有所偏差或其他看法欢迎大佬交流,共同进步~


完结 撒花 ฅ>ω<*ฅ