如何优雅的给RecyclerView添加头尾

前言

  RecyclerView的可定制化程度相较于ListView确实是方便了很多,但是RecyclerView是不支持添加头尾以及空布局的,经过一些实践,最终觉得对适配器进行扩展的方式是比较方便的。

内容

  这里就不在赘述,直接上代码了。

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
@SuppressWarnings("ALL")
public abstract class BaseRecyclerAdapter<T, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter {

private final int ITEM_TYPE = 0;
private final int EMPTY_TYPE = 99;
private final int BASE_HEADER_TYPE = 100;
private final int BASE_FOOTER_TYPE = 200;

protected Context context;
protected LayoutInflater inflater;
protected int resId;

protected List<T> dataSource;

protected SparseArray<View> headers;
protected SparseArray<View> footers;
protected View emptyView;

protected OnItemClickListener<T> onItemClickListener;
protected View.OnClickListener onClickListener;

protected boolean showHeaderFooterWhenEmpty;

public BaseRecyclerAdapter(@NonNull Context context, @LayoutRes int resId) {
this.context = context;
this.inflater = LayoutInflater.from(context);
this.resId = resId;

this.dataSource = new ArrayList<>();
this.headers = new SparseArray<>();
this.footers = new SparseArray<>();
}

public void clearDataSource() {
dataSource.clear();
}

public void addAll(List<T> list) {
dataSource.addAll(list);
}

public void addHeaderView(View header) {
if (headers.indexOfValue(header) < 0) {
headers.put(BASE_HEADER_TYPE + headers.size(), header);
}
}

public void addFooterView(View footer) {
if (footers.indexOfValue(footer) < 0) {
footers.put(BASE_FOOTER_TYPE + footers.size(), footer);
}
}

public int getHeaderCount() {
return headers.size();
}

public int getFooterCount() {
return footers.size();
}

public void setEmptyView(View view) {
this.emptyView = view;
}

public void setShowHeaderFooterWhenEmpty(boolean showHeaderFooterWhenEmpty) {
this.showHeaderFooterWhenEmpty = showHeaderFooterWhenEmpty;
}

public void setOnItemClickListener(OnItemClickListener<T> listener) {
this.onItemClickListener = listener;
}

public void setOnClickListener(View.OnClickListener listener) {
this.onClickListener = onClickListener;
}

@Override
public int getItemViewType(int position) {
if (emptyView != null && dataSource.isEmpty() && !showHeaderFooterWhenEmpty) {
return EMPTY_TYPE;
}

if (position < headers.size()) {
return headers.keyAt(position);
}

int index = position - headers.size();
int viewType;
if (dataSource.isEmpty()) {
if (emptyView == null) {
viewType = footers.keyAt(index);
} else if (index == 0) {
viewType = EMPTY_TYPE;
} else {
index = index - 1;
viewType = footers.keyAt(index);
}
} else {
if (index < dataSource.size()) {
viewType = ITEM_TYPE;
} else {
index = index - dataSource.size();
viewType = footers.keyAt(index);
}
}
return viewType;
}

@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// empty
if (viewType == EMPTY_TYPE) {
return new RecyclerView.ViewHolder(emptyView) {
};
}

// header
View view = headers.get(viewType);
if (view != null) {
return new RecyclerView.ViewHolder(view) {
};
}

// footer
view = footers.get(viewType);
if (view != null) {
return new RecyclerView.ViewHolder(view) {
};
}

// item
return createItemViewHolder(inflater.inflate(resId, parent, false));
}

protected abstract VH createItemViewHolder(View view);

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (getItemViewType(position) == ITEM_TYPE) {
final int index = position - headers.size();
final T obj = dataSource.get(index);
if (onItemClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onItemClickListener.onItemClicked(obj, index);
}
});
}
bindData((VH) holder, dataSource.get(index), index);
}
}

protected abstract void bindData(@NonNull VH h, T obj, int position);

@Override
public int getItemCount() {
if (emptyView != null && dataSource.isEmpty()) {
if (showHeaderFooterWhenEmpty) {
return headers.size() + 1 + footers.size();
} else {
return 1;
}
}
return headers.size() + dataSource.size() + footers.size();
}

@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
RecyclerView.LayoutManager lm = recyclerView.getLayoutManager();
if (lm instanceof GridLayoutManager) {
final GridLayoutManager glm = (GridLayoutManager) lm;
glm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
int type = getItemViewType(position);
// fix span count for header and footer and empty view
if (type == ITEM_TYPE) {
return 1;
}
return glm.getSpanCount();
}
});
}
}

public interface OnItemClickListener<T> {
void onItemClicked(T obj, int position);
}
}

  

本文标题:如何优雅的给RecyclerView添加头尾

文章作者:严方雄

发布时间:2018-07-15

最后更新:2018-11-01

原始链接:http://yanfangxiong.com/2018/07/15/如何优雅的给RecyclerView添加头尾/

0%