学习MultiViewAdapter——2
来源:互联网 发布:大数据教程百度云 编辑:程序博客网 时间:2024/05/22 14:03
本文讲到的关于MultiViewAdapter,是学习国外牛人在GitHub上的开源项目。具体的使用方法可以看Wiki。
接着昨天说的内容,昨天讲了其中的一个ItemBinder ,今天要说一下RecyclerAdapter 。
我们先来看看怎么实现一个多布局(代码与图片来自作者博客):
Adapter
//创建多布局的adapterpublic class MultiListAdapter extends RecyclerAdapter{ private DataListManager<Bird> birdDataManager; private DataListManager<Flower> flowerDataManager; public MultiListAdapter(Context context) { //将Mode放入DataListManager birdDataManager = new DataListManager<>(this); flowerDataManager = new DataListManager<>(this); //调用父类方法,将ModeManager放入 addDataManager(flowerDataManager); addDataManager(birdDataManager);//注册type布局类 registerBinder( new FlowerBinder(new SimpleDividerDecoration(context, SimpleDividerDecoration.VERTICAL))); registerBinder(new BirdBinder(new ThickItemDecorator(context))); }//添加数据 public void addBirds(List<Bird> dataList) { birdDataManager.set(dataList); } public void addFlowers(List<Flower> dataList) { flowerDataManager.addAll(dataList); }}
ItemBinder
一共两个ItemBinder,我这里贴一个,另一个基本一样。
public class BirdBinder extends ItemBinder<Bird, BirdBinder.ViewHolder> { BaseViewHolder.OnItemClickListener<Bird> listener; public BirdBinder(ItemDecorator itemDecorator) { super(itemDecorator); } public BirdBinder(ItemDecorator itemDecorator, BaseViewHolder.OnItemClickListener<Bird> listener) { super(itemDecorator); this.listener = listener; } @Override public BirdBinder.ViewHolder create(LayoutInflater layoutInflater, ViewGroup parent) { return new ViewHolder(layoutInflater.inflate(R.layout.item_bird, parent, false), listener); } @Override public void bind(ViewHolder holder, Bird item) { holder.textView.setText(item.getBirdName()); } @Override public boolean canBindData(Object item) { return item instanceof Bird; } @Override public int getSpanSize(int maxSpanCount) { return maxSpanCount; } static class ViewHolder extends BaseViewHolder<Bird> { private TextView textView; ViewHolder(View itemView, OnItemClickListener<Bird> listener) { super(itemView); textView = (TextView) itemView.findViewById(R.id.tv_bird_name); setItemClickListener(listener); } }}
这是一个非常简单的多布局实现,我们现在要去分析Adapter做了什么?这个Adapter与我们平时写的不一样,没有看到常规的if-else 去判断布局type,所以作者到底怎么去实现这种* 对model的使用无限制,view type可以有自己的span count 或者 ItemDecoration,而且我们还不必去写switch cases 或者 if-else 语句*
1 . RecyclerAdapter
我们看到MultiListAdapter extends RecyclerAdapter
,然后添加了ListData,注册了ItemBinder,最后将数据添加进去。点击去RecyclerAdapter
...省略了一些常量public final void addDataManager(BaseDataManager dataManager) { dataManagers.add(dataManager); } public final void registerBinder(ItemBinder binder) { if (!binders.contains(binder)) { binders.add(binder); } }...省略了一些常用的项点击,拖动事件
这里其实也没有什么,RecyclerAdapter extends CoreRecyclerAdapter
,主要提供了Data与ViewHolder交互的入口。那就看看CoreRecyclerAdapter
吧。
2 . CoreRecyclerAdapter extends RecyclerView.Adapter<ItemViewHolder>
//数据管理器的集合 final List<BaseDataManager> dataManagers = new ArrayList<>(); //UI与数据绑定的集合 final List<ItemBinder> binders = new ArrayList<>();
在代码中我们找到了那两个集合,哦 ,那么拿着这两个集合是怎么做到,不用写if-else就出来MultiView的效果呢?我们接着看,既然继承的是官方的RecyclerView.Adapter
,那我们就跟着它的方法执行顺序看吧。这里只介绍2个覆盖方法,另外两个下一章说:
- getItemCount()
@Override public final int getItemCount() { int itemCount = 0; for (BaseDataManager dataManager : dataManagers) { itemCount += dataManager.size(); } return itemCount; }
从这个方法可以看出遍历dataManagers,然后把各个DataList里面的数据相加,返回给adapter。所以我们可以写多个ItemBinder,也就是一个type一个ItemBinder,这样也可以复用。那么dataManager.size()这里面的数据哪来的呢?下一章讲吧 O(∩_∩)O~
- getItemViewType
@Override public final int getItemViewType(int adapterPosition) { //根据adapterPosition,得到ItemBinder ItemBinder baseBinder = getBinderForPosition(adapterPosition); if (null != baseBinder) { return binders.indexOf(baseBinder); } return super.getItemViewType(adapterPosition); }
看到这个关键方法了,这里我们需要知道getItemViewType
默认返回的是0哦,于是通过getBinderForPosition(adapterPosition);
获得itemBinder,然后返回指定元素的索引,看来这个getBinderForPosition
里面有干货,继续看…
ItemBinder getBinderForPosition(int adapterPosition) { //首先得到数据管理器 BaseDataManager dataManager = getDataManager(adapterPosition); for (ItemBinder baseBinder : binders) { //每个ItemBinder都会重写canBindData方法,判断当前的ItemBinder是什么,返回这个ItemBinder if (baseBinder.canBindData(dataManager.getItem(getItemPositionInManager(adapterPosition)))) { return baseBinder; } } throw new IllegalStateException("Binder not found for position. Position = " + adapterPosition); } //得到数据的manager BaseDataManager getDataManager(int adapterPosition) { //判断获取的dataManager是不是可以扩展头和脚的管理器 BaseDataManager dataManager = justGetDataManager(adapterPosition); if (dataManager instanceof DataGroupManager) { return ((DataGroupManager) dataManager).getDataManagerForPosition( getItemPositionInManager(adapterPosition)); } else { return dataManager; } } BaseDataManager justGetDataManager(int adapterPosition) { int processedCount = 0; for (BaseDataManager dataManager : dataManagers) { processedCount += dataManager.getCount(); //通过adapterPosition可以知道 if (adapterPosition < processedCount) { return dataManager; } } throw new IllegalStateException("Invalid position for DataManager!"); } //得到每个manager中屏幕显示item的position int getItemPositionInManager(int adapterPosition) { int itemCount; for (BaseDataManager dataManager : dataManagers) { itemCount = dataManager.getCount(); Log.w("KIMC", "itemCount = " + itemCount); Log.w("KIMC", "adapterPosition = " + adapterPosition); if (adapterPosition - itemCount < 0) { break; } //adapterPosition= adapterPosition- itemCount; adapterPosition -= itemCount; } // adapterPosition now refers to position in manager return adapterPosition; }
上面的方法一个套一个,我们一个一个看。
justGetDataManager
主要通过adapterPosition来获取对应的BaseDataManager。具体的做法是:假如我们添加了2个不同类型的type,那么根据adapterPosition与当前dataManager里面的数据,当遍历到第一个dataManagers的时候,与adapterPosition比较,如果小于dataManagers的count就返回当前的dataManagers,遍历第二次dataManagers的时候,与上一个dataManagers里面的数据相加,然后再比较,返回第二dataManagers。
到了getDataManager
中判断了当前dataManager是不是DataGroupManager的。(DataGroupManager主要是处理了有header的Item比如:可以折叠与展开的Item)。
最后在getBinderForPosition
中,获取到DataManager后,经过判断得到想要的itemBinder,getItemPositionInManager
主要处理了position的问题。如果传入了2种不同类型的type,那么遍历第一个dataManagers的时候,与adapterPosition比较,如果adapterPosition-第一次dataManagers的数量小于0的时候,重新遍历。到了第二个dataManagers的时候,adapterPosition - itemCount < 0不成立。adapterPosition的下标从0重新开始,也就是第二种typeView了。也就是随着用户滑动屏幕,position随着type布局的出现与消失而不断的从0-xx来变化。
我们实现多布局的时候,addDataManager()
的先后顺序决定着我们多布局在界面上添加的顺序,当然了,关于addDataManager()
这个方法也提供了重载方法,可以输入index,这样也方便我们开发。
到这里我们也就了解了,为什么不用写if-else就可以实现多布局了。明天准备说一说DataMananger的内容。
- 学习MultiViewAdapter——2
- 学习MultiViewAdapter——1
- 学习MultiViewAdapter——3
- 学习MultiViewAdapter——4
- javaEE学习—SSH学习前奏2
- jQuery 学习—2
- 【学习】——高效学习
- 机器学习—学习笔记
- 学习ICE——2
- android学习——2
- STM32CUBE学习——2
- hadoop学习——2
- Jmeter学习——2
- CGAL——学习2
- 黑马程序员——学习日记2 学习java概述
- RPG游戏学习——3.rpgmaker事件学习2
- 机器学习实战学习笔记2——决策树算法
- ARM9 mini2451裸机学习——LCD驱动学习 2
- Spring注入对象类型的属性
- 快速创建spring boot工程
- Spring的scope="prototype"属性
- 从 jquery 过渡至 angular 转战到 vue
- Python_类
- 学习MultiViewAdapter——2
- 教你如何写PRD文档
- Qt动态删除
- hello
- CentOs日常问题集锦(持续更新......)
- Material Design实战之ToolBar
- ios获取手机IP地址
- java 并发编程实战书籍学习 第五章,CountDownLatch,FutureTask,CyclicBarrier,Semaphore学习
- 【c#系列 二】从java到.net 基础