二级列表是项目中经常会用到的组件,本着学习新组件的思想,决定不用ExpandableListView,而是用RecyclerView实现。
为了不重复造轮子,在github上搜索一番,看到一个还不错的项目thoughtbot/expandable-recycler-view,这个项目封装好了二级列表的整个实现,使用起来也很简单,下载项目看一下sample就多清楚了。但是这个项目有个问题,不能更新数据,recyclerview数据是初始化的时候给定的,没有后续变更数据的操作,所以修改了一下这个项目。
1. 实现动态变更数据
ExpandableGroup类增加teamId,每个分组的唯一标识
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
29public class ExpandableGroup<T extends Parcelable> implements Parcelable {
private int teamId;
// ...
public ExpandableGroup(int teamId, String title, List<T> items) {
this.teamId = teamId;
this.title = title;
this.items = items;
}
protected ExpandableGroup(Parcel in) {
teamId = in.readInt();
// ..
}
public int getTeamId() {
return teamId;
}
public void setTeamId(int teamId) {
this.teamId = teamId;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(teamId);
// ...
}
}修改ExpandableList类的变量public boolean[] expandedGroupIndexes;该变量被用来记住当前分组是否展开,默认为false,用boolean数组不好的一点,在数据增加或者减少的时候,没办法把旧展开状态还原到新的数据中,修改为使用map,根据每个分组的id,来存储分组的展开状态,并在数据变更的时候,还原状态。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class ExpandableList {
public List<? extends ExpandableGroup> groups;
// 修改为使用map,对项目中其他使用该变量的地方相应的修改为根据teamId获取或更新展开状态
public SparseBooleanArray expandedGroupIndexes;
public ExpandableList(List<? extends ExpandableGroup> groups) {
this.groups = groups;
// 默认都为false
expandedGroupIndexes = new SparseBooleanArray();
for (int i = 0; i < groups.size(); i++) {
expandedGroupIndexes.put(groups.get(i).getTeamId(), false);
}
}
}在ExpandableRecyclerViewAdapter.java中,增加更新数据的方法,进行数据的更新。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public void setGroups(List<? extends ExpandableGroup> groups) {
// 保留一份老的展开状态的数据
SparseBooleanArray oldIndex = this.expandableList.expandedGroupIndexes.clone();
this.expandableList.groups = groups; // 设置新的数据
// 设置新的展开状态数据
this.expandableList.expandedGroupIndexes = new SparseBooleanArray();
for (int i = 0; i < groups.size(); i++) {
this.expandableList.expandedGroupIndexes.put(groups.get(i).getTeamId(), false);
}
SparseBooleanArray newIndex = this.expandableList.expandedGroupIndexes;
for (int i = 0; i < newIndex.size(); i++) {
for (int j = 0; j < oldIndex.size(); j++) {
// 如果含有老的数据的话,还原到新数据集
if (newIndex.keyAt(i) == oldIndex.keyAt(j)) {
newIndex.put(oldIndex.keyAt(j), oldIndex.get(oldIndex.keyAt(j)));
}
}
}
}这样便可实现动态修改二级列表的数据,弥补了原项目不能动态修改数据的一个不足。
2. 实现类似ExpandableListview的列表悬浮在顶部效果+可分页加载RecyclerView
这个功能使用比较简单的方法,在RecyclerView顶部增加一个view,在滑动的时候,该view一直在顶部展示,并且展示当前分组下的Group的名称和状态等。
- 顶部悬浮view实现
1 |
|
使用方就像正常的使用RecyclerView一样使用该自定义RecyclerView,最后顶部的悬浮view效果如下:
3. ExpandableRecyclerView实现分页加载
对于可能数据量很大的数据来说,分页加载是必不可少的,一次大量的加载请求数据会造成不必要的浪费。
1 | public class ExpandableRecyclerView extends RelativeLayout { |
改造完后,该项目基本实现了二级列表+动态更新+分页加载功能,算是一个比较完善的二级列表RecyclerView了,后续有时间继续研究一下看能否把RecyclerView的局部刷新功能也加上。最后,再次感谢thoughtbot/expandable-recycler-view项目,也是这个项目封装的比较好,才能实现这些改造。