学习MultiViewAdapter——4
来源:互联网 发布:linux java 打包 编辑:程序博客网 时间:2024/06/05 06:04
本文讲到的关于MultiViewAdapter,是学习国外牛人在GitHub上的开源项目。具体的使用方法可以看Wiki。
今天来说一说最后一块内容DataGroupManager
,DataGroupManger
可以是带有头的管理器,支持item的折叠与展开,之前讲的关于DataListManager
这个主要处理了单个ViewType
中数据的问题,库的作者为了方便人们调用添加了支持头的布局添加管理器。这里的“头”不是说“下拉刷新的那个头”。
我们先了解一下RecyclerView.adapter
数据刷新的几种方法:
notifyItemChanged(int position)
更新列表上指定position位置的数据notifyItemInserted(int position)
列表position位置添加一条数据,有动画效果notifyItemRemoved(int position)
列表position位置移除一条数据,有动画效果notifyItemMoved(int fromPosition, int toPosition)
列表fromPosition位置的数据移动到toPosition位置,有动画效果notifyItemRangeChanged(int positionStart, int itemCount)
列表从positionStart位置到itemCount数量的列表项进行数据刷新 ,有动画效果notifyItemRangeInserted(int positionStart, int itemCount)
列表从positionStart位置到itemCount数量的列表项批量添加数据时调用,有动画效果notifyItemRangeRemoved(int positionStart, int itemCount)
列表从positionStart位置到itemCount数量的列表项批量删除数据时调用,有动画效果
了解了上面关于一些刷新的方法之后,我们就来看看DataGroupManager
做了什么。
DataGroupManager
public class DataGroupManager<H, M> extends DataListUpdateManager<M> { private final DataItemManager<H> headerItemManager; public DataGroupManager(RecyclerAdapter adapter, H headerItem) { super(adapter); headerItemManager = new DataItemManager<>(adapter, headerItem); } public DataGroupManager(RecyclerAdapter adapter, H headerItem, @NonNull PayloadProvider<M> payloadProvider) { super(adapter, payloadProvider); headerItemManager = new DataItemManager<>(adapter, headerItem); } //...省略一部分代码 @Override void onGroupExpansionToggled() { ...省略一部分代码 } @Override M getItem(int dataItemPosition) { return super.getItem(dataItemPosition - 1); } @Override int size() { return headerItemManager.size() + (isExpanded ? super.size() : 0); } public final boolean add(M item) { boolean result = add(item, false); if (result && isExpanded) { onInserted(getDataList().size(), 1); } return result; } ...省略了其他添加的方法}
我们看到了DataGroupManager
的构造方法中直接就new DataItemManager()
,也就是给布局中添加了一个header,然后这个方法中定义了一些数据的添加,删除等方法。这些方法中已经计算了在有header的时候,集合的大小与item中的position的位置关系。那么我们看一下DataItemManager
这个方法。
DataItemManager
public final class DataItemManager<M> extends BaseDataManager<M> { public DataItemManager(RecyclerAdapter baseAdapter) { super(baseAdapter); } public DataItemManager(RecyclerAdapter baseAdapter, M item) { super(baseAdapter); getDataList().add(item); } public final void setItem(M item) { if (getDataList().size() == 0) { getDataList().add(item); onInserted(0, 1); } else { getDataList().set(0, item); onChanged(0, 1, null); } } public final void removeItem() { if (getDataList().size() > 0) { getDataList().clear(); onRemoved(0, 1); } }}
很简单,继承BaseDataManager
然后在构造方法中,直接把数据添加到集合中。然后提供了添加与删除Item的方法。
那么我们看看在实际中怎么使用的,先上一张效果图:
先看看实现这种效果的关键代码(完整代码可在sample中看到):
ExpandableGroupAdapter
@Override protected void setUpAdapter() { ExpandableGroupAdapter adapter = new ExpandableGroupAdapter( new SimpleDividerDecoration(this, SimpleDividerDecoration.VERTICAL)); //设置折叠的模式 adapter.setExpandableMode(RecyclerAdapter.EXPANDABLE_MODE_MULTIPLE); //设置Group折叠的模式 adapter.setGroupExpandableMode(RecyclerAdapter.EXPANDABLE_MODE_MULTIPLE); LinearLayoutManager llm = new LinearLayoutManager(getApplicationContext()); recyclerView.addItemDecoration(adapter.getItemDecorationManager()); recyclerView.setLayoutManager(llm); recyclerView.setAdapter(adapter); List<Bird> birds = new ArrayList<>(); for (int i = 0; i < 10; i++) { birds.add(new Bird("Bird " + i)); } adapter.addBirds(birds); List<Flower> flowers = new ArrayList<>(); for (int i = 0; i < 10; i++) { flowers.add(new Flower(i, "Flower " + i)); } adapter.addFlowers(flowers); List<String> dataList = new ArrayList<>(); for (int i = 1; i <= 5; i++) { dataList.add("Item " + i); } adapter.addItems(dataList); }
因为是sample,所以直接就在Activity里面模拟数据并且添加进去,这里面有一个ExpandableGroupAdapter
,我们点击去看看这个方法做了什么?
ExpandableGroupAdapter
public class ExpandableGroupAdapter extends RecyclerAdapter implements BaseViewHolder.OnItemClickListener<Bird> { private DataGroupManager<Header, Bird> birdsGroup; private DataGroupManager<Header, Flower> flowerGroup; private DataGroupManager<Header, String> expandableItemGroup; public ExpandableGroupAdapter(ItemDecorator dividerDecoration) { birdsGroup = new DataGroupManager<>(this, new Header("Birds")); flowerGroup = new DataGroupManager<>(this, new Header("Flowers")); expandableItemGroup = new DataGroupManager<>(this, new Header("Expandable Items")); addDataManager(birdsGroup); addDataManager(flowerGroup); addDataManager(expandableItemGroup); registerBinder(new ExpandableHeaderBinder()); registerBinder(new ExpandableItemBinder()); registerBinder(new BirdBinder(dividerDecoration, this)); registerBinder(new FlowerBinder(dividerDecoration)); } ...省略了为DataGroupManager设置数据的代码}
和实现most typeView holder的写法一样,只不过是多了一个Header,根据效果图,我们需要注意的是有两种显示效果,一种是一个Item有折叠效果,还有一个在Group中有多层折叠的效果,之前说过,点击事件这些方法都在ViewHolder中实现的,所以我们重点来看一下ExpandableHeaderBinder()
与ExpandableItemBinder()
两个类中怎么实现的该效果。
ExpandableItemBinder
public class ExpandableItemBinder extends ItemBinder<String, ExpandableItemBinder.ViewHolder> { ...省略create,bind,canBindData方法 static class ViewHolder extends BaseViewHolder<String> { public ViewHolder(View itemView) { super(itemView); ...省略找ID的代码 setItemClickListener(new OnItemClickListener<String>() { @Override public void onItemClick(View view, String item) { toggleItemExpansion(); ivIndicator.setImageResource( isItemExpanded() ? R.drawable.ic_expand_less : R.drawable.ic_expand_more); } }); } }}
ExpandableHeaderBinder
public class ExpandableHeaderBinder extends ItemBinder<Header, ExpandableHeaderBinder.ViewHolder> { ...省略create,bind,canBindData方法 static class ViewHolder extends BaseViewHolder<Header> { public ViewHolder(View itemView) { super(itemView); ...省略找ID的代码 setItemClickListener(new OnItemClickListener<Header>() { @Override public void onItemClick(View view, Header item) { toggleGroupExpansion(); ivIndicator.setImageResource( isItemExpanded() ? R.drawable.ic_expand_less : R.drawable.ic_expand_more); } }); } }}
现在发现,这两个ViewHolder中不同的仅仅是toggleItemExpansion();
与toggleGroupExpansion();
一个是设置单个Item点击折叠的效果,另一个是嵌套Group里面的。实现这两个方法的地方在CoreRecyclerAdapter
。
//用来存储是否是折叠或者展开的状态final SparseBooleanArray expandedItems = new SparseBooleanArray(); private void onItemExpansionToggled(int adapterPosition) { Log.w("jinzetao", "adapterPosition=" + adapterPosition); switch (expandableMode) { //只能展开一个Item,另一个Item会收起来 case EXPANDABLE_MODE_SINGLE: if (lastExpandedIndex != -1) { //折叠 expandedItems.put(lastExpandedIndex, false); getDataManager(lastExpandedIndex).onItemExpansionToggled( getItemPositionInManager(lastExpandedIndex)); } if (lastExpandedIndex == adapterPosition) { //重置 lastExpandedIndex = -1; return; } //展开 expandedItems.put(adapterPosition, true); //获得当前的数据Manager然后调用onChanged(position, 1, null); // getItemPositionInManager(adapterPosition)这里是屏幕显示的position,每个ViewType都是从0开始 getDataManager(adapterPosition).onItemExpansionToggled( getItemPositionInManager(adapterPosition)); lastExpandedIndex = adapterPosition; break; //多个Item都会展开 case EXPANDABLE_MODE_MULTIPLE: expandedItems.put(adapterPosition, !expandedItems.get(adapterPosition, false)); getDataManager(adapterPosition).onItemExpansionToggled( getItemPositionInManager(adapterPosition)); break; case EXPANDABLE_MODE_NONE: default: break; } } private void onGroupExpansionToggled(int adapterPosition) { switch (groupExpandableMode) { case EXPANDABLE_MODE_SINGLE: if (lastExpandedIndex == adapterPosition) { return; } if (lastExpandedIndex != -1) { getDataManager(lastExpandedIndex).onGroupExpansionToggled(); } getDataManager(adapterPosition).onGroupExpansionToggled(); lastExpandedIndex = adapterPosition; break; case EXPANDABLE_MODE_MULTIPLE: expandedItems.put(adapterPosition, !expandedItems.get(adapterPosition, false)); justGetDataManager(adapterPosition).onGroupExpansionToggled(); break; case EXPANDABLE_MODE_NONE: default: break; } }
Item与GroupItem在实现上基本一样,只是GroupItem把内部Item折叠的方法交给了子类去处理,需要用户自己实现。单个的Item中,将会更新expandedItems
的状态,这个状态决定着需要折叠的数据是否显示,最后调用BaseManager中的onItemExpansionToggled,去刷新界面。简单的关于header的添加就说到这里,然后我们在说一下怎么添加“脚”也就是“加载更多”。
InfiniteLoadingHelper
这个类简单的封装了需要加载更多的逻辑,也是把加载更多这个当做了一个新的Type来处理的。和创建一个普通的ItemBinder一样,只不过多了一个关于RecyclerView滑动监听的接口,在计算出当前是最后一个position的时候,然后加载下一页。加载完成以后,然后将这个Item 移除掉。完整的代码可以在sample中找到。
public abstract class InfiniteLoadingHelper { ...省略一部分代码 public InfiniteLoadingHelper(@LayoutRes int layoutId, int totalPageCount) { this.itemBinder = new InfiniteLoadingBinder(layoutId); this.totalPageCount = totalPageCount; this.infiniteScrollListener = new InfiniteScrollListener(this); } public ItemBinder<String, ItemViewHolder<String>> getItemBinder() { return itemBinder; } @RestrictTo(RestrictTo.Scope.LIBRARY) public void setDataItemManager(DataItemManager<String> dataItemManager) { canLoadMore = true; this.dataItemManager = dataItemManager; } public void markCurrentPageLoaded() { isLoading = false; if (!canLoadMore) { completeLoading(); } } private void loadNextPage() { isLoading = true; onLoadNextPage(currentPage++); if (currentPage == totalPageCount) { canLoadMore = false; } } ...省略一部分代码 private static class InfiniteLoadingBinder extends ItemBinder<String, ItemViewHolder<String>> { ...省略一部分代码 } private static class InfiniteScrollListener extends RecyclerView.OnScrollListener { private final InfiniteLoadingHelper loadingHelper; InfiniteScrollListener(InfiniteLoadingHelper loadingHelper) { this.loadingHelper = loadingHelper; } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { if (dy > 0 && !loadingHelper.isLoading && loadingHelper.canLoadMore) { int totalItemCount = recyclerView.getLayoutManager().getItemCount(); int lastVisibleItemPosition = 0; //对瀑布流的视图进行了特殊的处理 if (recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager) { int[] lastVisibleItemPositions = ((StaggeredGridLayoutManager) recyclerView.getLayoutManager()).findLastVisibleItemPositions( null); lastVisibleItemPosition = lastVisibleItemPositions[lastVisibleItemPositions.length - 1]; } else if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) { lastVisibleItemPosition = ((LinearLayoutManager) recyclerView.getLayoutManager()).findLastVisibleItemPosition(); } if (lastVisibleItemPosition + 1 >= totalItemCount) { loadingHelper.loadNextPage(); } } } }}
那么使用的时候,传给InfiniteLoadingHelper
布局,count,然后设置滑动监听,就可以用了。
infiniteLoadingHelper = new InfiniteLoadingHelper(R.layout.item_loading_footer, 10) { @Override public void onLoadNextPage(int page) { currentPage = page + 1; handler.postDelayed(runnable, 2000); } }; adapter.setInfiniteLoadingHelper(infiniteLoadingHelper); recyclerView.addOnScrollListener(infiniteLoadingHelper.getScrollListener()); recyclerView.addItemDecoration(adapter.getItemDecorationManager()); recyclerView.setLayoutManager(llm); recyclerView.setAdapter(adapter); loadData();private void loadData() { List<Flower> flowers = new ArrayList<>(); for (int i = 1; i <= 10; i++) { flowers.add(new Flower(i, "Flower " + (i + currentPage * 10))); } adapter.addFlowers(flowers); infiniteLoadingHelper.markCurrentPageLoaded(); }
效果图如下:
好了,这个库就说到这里了,学到的东西也不少。
- 解耦Adapter,让每个ViewHolder实现重复使用。(这个我觉得是业务逻辑的问题)
- 不写if-else实现多ViewType
- 封装ItemDecorator让每个ItemBinder都能设置自己的
- DiffUtil的使用
- Item的一些常用逻辑的封装
- 一些注解的使用
连续下了一个星期的冰雨,外面的温度降到了12摄氏度。
于是人们都穿起了厚厚的羽绒衣。
打代码的时候,连胳膊都抬不起来了。
ヾ(。ꏿ﹏ꏿ)ノ゙
- 学习MultiViewAdapter——4
- 学习MultiViewAdapter——1
- 学习MultiViewAdapter——2
- 学习MultiViewAdapter——3
- 【学习】——高效学习
- 机器学习—学习笔记
- Web开发学习笔记4——CSS学习笔记
- j2me学习笔记【4】——Item类的学习
- 《Python学习手册》学习笔记——第4章
- UE4学习笔记(4)——材质学习
- 机器学习笔记4——生成学习算法
- 机器学习(4)—— Adaboost学习
- Spring学习笔记(4)——IoC学习
- NLP深度学习 —— CS224学习笔记4
- 《机器学习实战》学习笔记4——决策树
- 4、HTML 学习记录——元素学习
- 机器学习(4)——贝叶斯学习(一)
- 网格的学习—4
- 关于JavaScript中 arguments 的理解
- FragmentTabHost底部切换
- CentOS 7 mysql安装说明
- 1.git安装及创建版本库,git init,git add,git commit
- c++二维数组斜遍历,折线遍历
- 学习MultiViewAdapter——4
- CoordinatorLayout中使用WebView冲突
- sql
- 二分法——while等号
- HDU-6004-Periodical Cicadas
- 可变参数列表解析
- 201412-2 Z字形扫描 ccf
- js之初识函数
- 通达OA智能开发平台CRM系统 实现数据的自动计算