RecyclerView的通用适配器

最近闲来无事就想抽象出一个RecyclerView通用适配器,提高开发效率,而不需要再去考虑ViewHolder、控件初始化、以及实现BaseAdapter的其他三个必须实现的函数,本文借鉴了网上的一些代码。

#BaseRecyclerAdapter代码

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
public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter<RecyclerHolder> {
protected List<T> mDatas;
protected final int mLayoutId;
protected boolean isScrolling;
protected Context mContext;
protected OnItemClickListener mOnItemClickListener;
protected OnItemLongClickListener mOnItemLongClickListener;
public BaseRecyclerAdapter(RecyclerView v, Collection<T> datas, int layoutId) {
if (datas == null) {
mDatas = new ArrayList<>();
} else if (datas instanceof List) {
mDatas = (List<T>) datas;
} else {
mDatas = new ArrayList<>(datas);
}
mLayoutId = layoutId;
mContext = v.getContext();
v.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
isScrolling = !(newState == RecyclerView.SCROLL_STATE_IDLE);
if (!isScrolling) {
notifyDataSetChanged();
}
}
});
}
/**
* Recycler适配器填充方法
*
* @param holder viewholder
* @param item
* @param isScrolling RecyclerView是否正在滚动
*/
public abstract void convert(RecyclerHolder holder, T item, int position, boolean isScrolling);
@Override
public RecyclerHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerHolder holder = RecyclerHolder.createViewHolder(mContext, parent, mLayoutId);
setListener(parent, holder, viewType);
return holder;
}
protected boolean isEnabled(int viewType) {
return true;
}
protected void setListener(ViewGroup parent, final RecyclerHolder holder, int viewType) {
if (!isEnabled(viewType)) return;
holder.getConvertView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnItemClickListener != null) {
int position = holder.getAdapterPosition();
mOnItemClickListener.onItemClick(v, holder, position);
}
}
});
holder.getConvertView().setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mOnItemLongClickListener != null) {
int position = holder.getAdapterPosition();
return mOnItemLongClickListener.onItemLongClick(v, holder, position);
}
return false;
}
});
}
@Override
public void onBindViewHolder(RecyclerHolder holder, int position) {
convert(holder, mDatas.get(position), position, isScrolling);
}
@Override
public int getItemCount() {
return mDatas.size();
}
public BaseRecyclerAdapter<T> refreshData(Collection<T> datas) {
if (datas == null) {
mDatas = new ArrayList<>();
} else if (datas instanceof List) {
mDatas = (List<T>) datas;
} else {
mDatas = new ArrayList<>(datas);
}
return this;
}
public List<T> getDatas() {
return mDatas;
}
public interface OnItemClickListener {
void onItemClick(View view, RecyclerView.ViewHolder holder, int position);
}
public interface OnItemLongClickListener {
boolean onItemLongClick(View view, RecyclerView.ViewHolder holder, int position);
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.mOnItemClickListener = onItemClickListener;
}
public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) {
this.mOnItemLongClickListener = onItemLongClickListener;
}
}

#RecyclerHolder代码

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
public class RecyclerHolder extends RecyclerView.ViewHolder {
private final SparseArray<View> mViews;
private View mConvertView;
private Context mContext;
public RecyclerHolder(Context context, View itemView) {
super(itemView);
mContext = context;
mConvertView = itemView;
//一般不会超过8个吧
this.mViews = new SparseArray<View>(8);
}
public static RecyclerHolder createViewHolder(Context context, View itemView) {
RecyclerHolder holder = new RecyclerHolder(context, itemView);
return holder;
}
public static RecyclerHolder createViewHolder(Context context,
ViewGroup parent, int layoutId) {
View itemView = LayoutInflater.from(context).inflate(layoutId, parent,
false);
RecyclerHolder holder = new RecyclerHolder(context, itemView);
return holder;
}
public SparseArray<View> getAllView() {
return mViews;
}
/**
* 通过控件的Id获取对于的控件,如果没有则加入views
*
* @param viewId
* @return
*/
@SuppressWarnings("unchecked")
public <T extends View> T getView(int viewId) {
View view = mViews.get(viewId);
if (view == null) {
view = mConvertView.findViewById(viewId);
mViews.put(viewId, view);
}
return (T) view;
}
public View getConvertView() {
return mConvertView;
}
/**
* 为TextView设置字符串
*
* @param viewId
* @param text
* @return
*/
public RecyclerHolder setText(int viewId, String text) {
TextView view = getView(viewId);
view.setText(text);
return this;
}
/**
* 为ImageView设置图片
*
* @param viewId
* @param drawableId
* @return
*/
public RecyclerHolder setImageResource(int viewId, int drawableId) {
ImageView view = getView(viewId);
view.setImageResource(drawableId);
return this;
}
/**
* 为ImageView设置图片
*
* @param viewId
* @param bm
* @return
*/
public RecyclerHolder setImageBitmap(int viewId, Bitmap bm) {
ImageView view = getView(viewId);
view.setImageBitmap(bm);
return this;
}
public RecyclerHolder setImageDrawable(int viewId, Drawable drawable) {
ImageView view = getView(viewId);
view.setImageDrawable(drawable);
return this;
}
public RecyclerHolder setProgress(int viewId, int progress) {
ProgressBar view = getView(viewId);
view.setProgress(progress);
return this;
}
public RecyclerHolder setProgress(int viewId, int progress, int max) {
ProgressBar view = getView(viewId);
view.setMax(max);
view.setProgress(progress);
return this;
}
public RecyclerHolder setRating(int viewId, float rating) {
RatingBar view = getView(viewId);
view.setRating(rating);
return this;
}
public RecyclerHolder setRating(int viewId, float rating, int max) {
RatingBar view = getView(viewId);
view.setMax(max);
view.setRating(rating);
return this;
}
public RecyclerHolder setChecked(int viewId, boolean checked) {
Checkable view = (Checkable) getView(viewId);
view.setChecked(checked);
return this;
}
public RecyclerHolder setTag(int viewId, Object tag) {
View view = getView(viewId);
view.setTag(tag);
return this;
}
public RecyclerHolder setTag(int viewId, int key, Object tag) {
View view = getView(viewId);
view.setTag(key, tag);
return this;
}
public RecyclerHolder setBackgroundColor(int viewId, int color) {
View view = getView(viewId);
view.setBackgroundColor(color);
return this;
}
public RecyclerHolder setBackgroundRes(int viewId, int backgroundRes) {
View view = getView(viewId);
view.setBackgroundResource(backgroundRes);
return this;
}
public RecyclerHolder setTextColor(int viewId, int textColor) {
TextView view = getView(viewId);
view.setTextColor(textColor);
return this;
}
public RecyclerHolder setTextColorRes(int viewId, int textColorRes) {
TextView view = getView(viewId);
view.setTextColor(mContext.getResources().getColor(textColorRes));
return this;
}
/**
* 设置透明度
*
* @param viewId
* @param value
* @return
*/
@SuppressLint("NewApi")
public RecyclerHolder setAlpha(int viewId, float value) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
getView(viewId).setAlpha(value);
} else {
AlphaAnimation alpha = new AlphaAnimation(value, value);
alpha.setDuration(0);
alpha.setFillAfter(true);
getView(viewId).startAnimation(alpha);
}
return this;
}
public RecyclerHolder setVisible(int viewId, boolean visible) {
View view = getView(viewId);
view.setVisibility(visible ? View.VISIBLE : View.GONE);
return this;
}
/**
* 点击事件监听
*
* @param viewId
* @param listener
* @return
*/
public RecyclerHolder setOnClickListener(int viewId,
View.OnClickListener listener) {
View view = getView(viewId);
view.setOnClickListener(listener);
return this;
}
/**
* 触摸事件
*
* @param viewId
* @param listener
* @return
*/
public RecyclerHolder setOnTouchListener(int viewId,
View.OnTouchListener listener) {
View view = getView(viewId);
view.setOnTouchListener(listener);
return this;
}
/**
* 长按事件
*
* @param viewId
* @param listener
* @return
*/
public RecyclerHolder setOnLongClickListener(int viewId,
View.OnLongClickListener listener) {
View view = getView(viewId);
view.setOnLongClickListener(listener);
return this;
}
}

实现原理

RecyclerAdapter中规范了Holder,加入了onCreateViewHolder()和onBindViewHolder()方法分别来实现ViewHolder的创建和对Holder中的控件设置内容。
但是适配器写多了以后我们就会发现,其实这两个函数中写的内容也是重复的,于是就有了RecyclerHolder这个我们自己封装的Holder。 与平时我们自己实现的ViewHolder最大的不同在于,我们以前定义ViewHolder都是一个item里面要用哪个控件就定义哪个控件,而为了通用,我们抽出一个集合类存放这些Views, 使用了SparseArray来替代我们的Map,主要是考虑性能(相对的。

还做了一个小小的优化就是在我们我适配器中声明一个全局的boolean变量用来保存此刻是否在滚动,然后通过给RecyclerView设置滚动监听,然后在滚动监听器的onScrollStateChanged()方法中给boolean值赋值,看是否在滚动,这样就可以根据滚动状态的不同来判断:比如正在滚动的时候就只显示内存缓存的图片,如果内存缓存中没有就显示一张默认图片;而如果没有在滚动就采用正常的图片加载方案去加载网络或者缓存中的图片。

热评文章