学习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);        }    }}

效果图来自作者Wiki


这是一个非常简单的多布局实现,我们现在要去分析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的内容。


原创粉丝点击