最近有RecyclerView点击展开、折叠item的需求,其中一种写法是利用两个RecyclerView实现,但这样效率不高。因此采用单层RecyclerView来实现此需求。
简单起见,只展示一个bookName
private String bookName;
privateint index;privateboolean isShow;// 展开状态private String categoryName;private List<ChildBookItem> childBookItems;// 子item列表
index表示在item集合中此CategoryItem的位置(不算ChildBookItem的数量);
List childBookItems 是此Category在展开状态下所包含的子item集合,只用于记录对应关系,并不参与绘制UI。
private List<BookShelf>initData(){ BookShelf bookShelf1=newBookShelf(); bookShelf1.setName("科幻类"); String[] books1=newString[]{"三体","流浪地球","降临"}; bookShelf1.setBooks(Arrays.asList(books1)); mDatas.add(bookShelf1); BookShelf bookShelf2=newBookShelf(); bookShelf2.setName("政治类"); String[] books2=newString[]{"美国陷阱","从赫鲁晓夫到普京","为什么是以色列","南京大屠杀"}; bookShelf2.setBooks(Arrays.asList(books2)); mDatas.add(bookShelf2); BookShelf bookShelf3=newBookShelf(); bookShelf3.setName("文学类"); String[] books3=newString[]{"我们仨","小姨多鹤","我与地坛","黄金时代","雪国"}; bookShelf3.setBooks(Arrays.asList(books3)); mDatas.add(bookShelf3);return mDatas;}
由于初始不展示子item,所以不需要设置ChildBookItems的内容。此时定义的Adapter绑定的集合类型为Object,既包含CategoryItem,也包括ChildBookItem,所以不指定具体类型。
private List<Object> mList=newArrayList<>();// item组装数据private List<CategoryItem>initItem(){ List<BookShelf> bookShelves=initData(); List<CategoryItem> items=newArrayList<>();for(int i=0; i< bookShelves.size(); i++){ BookShelf bookShelf= bookShelves.get(i); CategoryItem categoryItem=newCategoryItem(); categoryItem.setIndex(i); categoryItem.setShow(false); categoryItem.setCategoryName(bookShelf.getName()); categoryItem.setChildBookItems(newArrayList<ChildBookItem>()); items.add(categoryItem);}return items;}
此时的items包含了三条数据,均为父item类型
BookViewHolder与CategoryViewHolder均为继承BaseViewHolder的ViewHolder,可在两个文件中分别进行item相关UI展示。
下边为Adapter部分关键代码:
public BaseViewHolderonCreateViewHolder(@NonNull ViewGroup viewGroup,int i){switch(i){case TYPE_CATEGORY:returnnewCategoryViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_category_item, viewGroup,false),this);case TYPE_BOOK:returnnewBookViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_item_book, viewGroup,false));default:returnnewBaseViewHolder(newLinearLayout(viewGroup.getContext())){@OverridepublicvoidbindView(List list, Object obj){}};}}@OverridepublicintgetItemViewType(int position){ Object obj= mDatas.get(position);if(objinstanceofCategoryItem){return TYPE_CATEGORY;}elseif(objinstanceofChildBookItem){return TYPE_BOOK;}return-1;}@OverridepublicvoidonBindViewHolder(@NonNull BaseViewHolder baseViewHolder,int i){ baseViewHolder.bindView(mDatas, mDatas.get(i));}
mList.addAll(mSelectedPosition + 1, childBookItems):将ChildBookItem集合加入到适配器绑定数据集合中,位置在刚刚点击的父item后一位;
mSelectedPosition:为刚刚点击的父item的position;
categoryItem.setChildBookItems(childBookItems):确定父item与子item集合的对应关系,方便后边折叠item时候直接从mList中删除此集合。
// 展开子itemprivatevoidaddChildItems(int index){ List<String> bookList= mDatas.get(index).getBooks(); List<ChildBookItem> childBookItems=newArrayList<>();for(int i=0; i< bookList.size(); i++){ ChildBookItem item=newChildBookItem(); item.setBookName(bookList.get(i)); childBookItems.add(item);} mList.addAll(mSelectedPosition+1, childBookItems);// 添加子item CategoryItem categoryItem=(CategoryItem) mList.get(mSelectedPosition); categoryItem.setChildBookItems(childBookItems); mAdapter.notifyDataSetChanged();}
若此时点击最后一个父item,可看到mList中前三条数据为CategoryItem类型;后五条数据为ChildBookItem类型,并与第三条CategoryItem的子item列表内容相同。
mList.removeAll(item.getChildBookItems()): 由于之前展开item的时候已经设置好了CategoryItem与ChildBookItem之间的对应关系,所以可通过此行代码直接从mList中删除子item。
privatevoidremoveChildItems(){ CategoryItem item=(CategoryItem)mList.get(mSelectedPosition); mList.removeAll(item.getChildBookItems()); item.setChildBookItems(newArrayList<ChildBookItem>()); mAdapter.notifyDataSetChanged();}
可在这里下载单层RecyclerView实现点击展开、折叠效果的demo