? ? ? ?今天給大伙兒分享一個用RecyclerView實現收縮分組懸浮列表的功能。如果只是想實現分組收縮的功能ExpandListView就完全可以做到了,這次咱們不僅要實現伸展收縮功能,還得實現分組懸浮,同時支持懸浮起來的item也是可點擊的。
一、效果圖
RecyclerView伸展收縮分組懸浮.gif
二、實現過程
? ? ? ?咱們要實現的目標:
- 每個分組都是可以伸展和收縮(ExpandListView效果)。
- 滑動過程中每個分組的父標題要一直固定在頂部(分組懸浮功能)。
- 在每個分組的父標題懸浮在頂部的時候支持點擊功能。
? ? ? ?關于分組懸浮功能,大家可以參考之前的文章RecyclerView分組懸浮列表。里面也增加了分組懸浮的時候的點擊功能。
? ? ? ?要實現伸展收縮的功能,首先咱們就得想辦法封裝每個分組Entity。每個分組包含三部分信息:標題Entity、子項Entity的list、當前分組狀態(展開還是收縮)。
/**
* 每個分組對應的entity
*
* @param <G> 標題欄entity
* @param <S> 子項entity
*/
public class ExpandGroupItemEntity<G, S> {
/**
* 分組對應的標題欄
*/
private G mParent;
/**
* 分組里面的子項
*/
private List<S> mChildList;
/**
* 分組展開還是收起
*/
private boolean mExpand;
public G getParent() {
return mParent;
}
public void setParent(G parent) {
mParent = parent;
}
public List<S> getChildList() {
return mChildList;
}
public void setChildList(List<S> childList) {
mChildList = childList;
}
public boolean isExpand() {
return mExpand;
}
public void setExpand(boolean expand) {
mExpand = expand;
}
}
這里為了方便大伙兒適應不用數據,所以用了泛型
? ? ? ?Group Entity封裝好了之后。就是對Adapter的封裝了。Adapter里面有兩種item type :每個分組的父item type、分組的子item type,然后控制好adapter里面每個position位置上的item屬于哪個分組,對應的是分組的父item還是子item。解決了這些問題我們需要實現的功能就都出來了。Adapter封裝代碼如下:
public abstract class RecyclerExpandBaseAdapter<G, C, VH extends RecyclerView.ViewHolder> extends PinnedHeaderAdapter<VH> {
protected static final int VIEW_TYPE_ITEM_TIME = 0;
protected static final int VIEW_TYPE_ITEM_CONTENT = 1;
protected List<ExpandGroupItemEntity<G, C>> mDataList;
protected SparseArray<ExpandGroupIndexEntity> mIndexMap;
public RecyclerExpandBaseAdapter() {
this(null);
}
public RecyclerExpandBaseAdapter(List<ExpandGroupItemEntity<G, C>> dataList) {
mDataList = dataList;
mIndexMap = new SparseArray<>();
}
public void setData(List<ExpandGroupItemEntity<G, C>> dataList) {
mDataList = dataList;
mIndexMap.clear();
notifyDataSetChanged();
}
public List<ExpandGroupItemEntity<G, C>> getData() {
return mDataList;
}
@Override
public boolean isPinnedPosition(int position) {
return getItemViewType(position) == VIEW_TYPE_ITEM_TIME;
}
@Override
public int getItemViewType(int position) {
int count = 0;
for (ExpandGroupItemEntity<G, C> item : mDataList) {
count = count + 1;
if (position == count - 1) {
return VIEW_TYPE_ITEM_TIME;
}
if (item.getChildList() != null && item.isExpand()) {
count = count + item.getChildList().size();
}
if (position < count) {
return VIEW_TYPE_ITEM_CONTENT;
}
}
throw new IllegalArgumentException("getItemViewType exception");
}
@Override
public int getItemCount() {
if (mDataList == null || mDataList.isEmpty()) {
return 0;
}
int count = 0;
for (int group = 0; group < mDataList.size(); group++) {
ExpandGroupItemEntity<G, C> item = mDataList.get(group);
//標題
count = count + 1;
mIndexMap.put(count - 1, new ExpandGroupIndexEntity(group, -1, item.getChildList() == null ? 0 : item.getChildList().size()));
int childStartPosition = count;
if (item.getChildList() != null && item.isExpand()) {
//sub
count = count + item.getChildList().size();
}
int childEndPosition = count;
for (int loop = childStartPosition; loop < childEndPosition; loop++) {
mIndexMap.put(loop, new ExpandGroupIndexEntity(group, loop - childStartPosition,
item.getChildList() == null ? 0 : item.getChildList().size()));
}
}
return count;
}
}
? ? ? ?關于具體的細節文章中介紹的比較簡單,更加具體的細節大伙兒可以參考代碼實例下載地址(注意是recyclerexpand對應的module)