BaseRecyclerViewAdapterHelper源码解读(七) 多布局

来源:互联网 发布:python中编码问题 编辑:程序博客网 时间:2024/06/04 23:35

多布局

多布局也是在平时的开发中使用得比较多,比如QQ好友动态如果是用的RecyclerView来实现的话,那么顶部是头布局,中间有每个人的动态是普通的item布局,中间穿插的广告又是另一种类型.

此篇文章为BaseRecyclerViewAdapterHelper源码解读第七篇,开源库地址,如果没有看过之前6篇文章的同学可以先去看看,大神可直接跳过.

BaseRecyclerViewAdapterHelper源码解读(一) 封装简单的adapter和万能的BaseViewHolder

BaseRecyclerViewAdapterHelper源码解读(二) 添加header和footer

BaseRecyclerViewAdapterHelper源码解读(三) 添加动画

BaseRecyclerViewAdapterHelper源码解读(四) 上拉加载更多

BaseRecyclerViewAdapterHelper源码解读(五) header和footer完善

BaseRecyclerViewAdapterHelper源码解读(六) 分组布局

使用

优点:
- 简单配置、无需重写额外方法。
- 可以设置默认布局类型
- 可以设置item布局的跨度
- 轻松添加新布局类型

使用方法:

1.写一个实体类,必须实现MultiItemEntity接口,并且尽量有itemType(用于标识该item是什么type)和spanSize(该item的跨度).

public class MultipleItem implements MultiItemEntity {    public static final int TEXT = 1;    public static final int IMG = 2;    public static final int IMG_TEXT = 3;    public static final int TEXT_SPAN_SIZE = 3;    public static final int IMG_SPAN_SIZE = 1;    public static final int IMG_TEXT_SPAN_SIZE = 4;    public static final int IMG_TEXT_SPAN_SIZE_MIN = 2;    private int itemType;    /**     * 跨度     */    private int spanSize;    public MultipleItem(int itemType, int spanSize, String content) {        this.itemType = itemType;        this.spanSize = spanSize;        this.content = content;    }    public MultipleItem(int itemType, int spanSize) {        this.itemType = itemType;        this.spanSize = spanSize;    }    public int getSpanSize() {        return spanSize;    }    public void setSpanSize(int spanSize) {        this.spanSize = spanSize;    }    private String content;    public String getContent() {        return content;    }    public void setContent(String content) {        this.content = content;    }    @Override    public int getItemType() {        return itemType;    }}

2.定义一个adapter,继承自BaseMultiItemQuickAdapter(必须),然后在构造方法中添加你这个RecyclerView的相关的item全部添加上。
然后在convert()方法里面绑定数据即可,绑定数据的时候记得如果添加了header,那么需要索引需要-1。

public class MultipleItemQuickAdapter extends BaseMultiItemQuickAdapter<MultipleItem, BaseViewHolder> {    public MultipleItemQuickAdapter(Context context, List data) {        super(data);        addItemType(MultipleItem.TEXT, R.layout.item_text_view);        addItemType(MultipleItem.IMG, R.layout.item_image_view);        addItemType(MultipleItem.IMG_TEXT, R.layout.item_img_text_view);    }    @Override    protected void convert(BaseViewHolder helper, MultipleItem item) {        switch (helper.getItemViewType()) {            case MultipleItem.TEXT:                helper.setText(R.id.tv, item.getContent());                break;            case MultipleItem.IMG_TEXT:                switch (helper.getLayoutPosition() %                        2) {                    case 0:                        helper.setImageResource(R.id.iv, R.mipmap.animation_img1);                        break;                    case 1:                        helper.setImageResource(R.id.iv, R.mipmap.animation_img2);                        break;                }                break;        }    }}

定做一个BaseMultiItemQuickAdapter

在定制adapter之前,我们先来了解一下SparseIntArray

SparseIntArrays map integers to integers. Unlike a normal array of integers, there can be gaps in the indices. It is intended to be more memory efficient than using a HashMap to map Integers to Integers, both because it avoids auto-boxing keys and values and its data structure doesn't rely on an extra entry object for each mapping.Note that this container keeps its mappings in an array data structure, using a binary search to find keys. The implementation is not intended to be appropriate for data structures that may contain large numbers of items. It is generally slower than a traditional HashMap, since lookups require a binary search and adds and removes require inserting and deleting entries in the array. For containers holding up to hundreds of items, the performance difference is not significant, less than 50%.It is possible to iterate over the items in this container using keyAt(int) and valueAt(int). Iterating over the keys using keyAt(int) with ascending values of the index will return the keys in ascending order, or the values corresponding to the keys in ascending order in the case of valueAt(int).上面是官方介绍,下面是翻译:SparseIntArrays将整数映射到整数。与正常的整数数组不同,索引中可能存在差距。它旨在比使用HashMap将整数映射到整数更有效率,因为它避免了自动打包(装箱)键和值,并且其数据结构不依赖于每个映射的额外的条目对象。请注意,此容器将其映射保存在数组数据结构中,使用二进制搜索查找密钥。该实现并不适用于可能包含大量项目的数据结构。它通常比传统的HashMap更慢,因为查找需要二进制搜索,并添加和删除需要插入和删除数组中的条目。对于容纳数百种物品的容器,性能差异不显着,小于50%。可以使用keyAt(int)和valueAt(int)迭代此容器中的项目。使用keyAt(int)使用keyAt(int)迭代索引的值将以升序返回键值,或者在valueAt(int)的情况下按升序对应的键值。

由于我们是需要实现多布局,于是我们需要引入不同的type和对应的不同的布局,这里开源库中使用的是SparseIntArray来存储这些数据.key是type,value是layoutResId.

下面我们来看看adapter源码

public abstract class BaseMultiItemQuickAdapter<T extends MultiItemEntity, K extends BaseViewHolder> extends BaseQuickAdapter<T, K> {    /**     * layouts indexed with their types     * key是type,value是layoutResId     */    private SparseIntArray layouts;    private static final int DEFAULT_VIEW_TYPE = -0xff;    public static final int TYPE_NOT_FOUND = -404;    /**     * Same as QuickAdapter#QuickAdapter(Context,int) but with     * some initialization data.     *     * @param data A new list is created out of this one to avoid mutable list     */    public BaseMultiItemQuickAdapter(List<T> data) {        super(data);    }    @Override    protected int getDefItemViewType(int position) {        Object item = mData.get(position);        // 实体类必须实现MultiItemEntity接口  不然不知道item的类型        if (item instanceof MultiItemEntity) {            return ((MultiItemEntity) item).getItemType();        }        return DEFAULT_VIEW_TYPE;    }    /**     * 设置默认的type的布局     */    protected void setDefaultViewTypeLayout(@LayoutRes int layoutResId) {        addItemType(DEFAULT_VIEW_TYPE, layoutResId);    }    @Override    protected K onCreateDefViewHolder(ViewGroup parent, int viewType) {        return createBaseViewHolder(parent, getLayoutId(viewType));    }    private int getLayoutId(int viewType) {        return layouts.get(viewType, TYPE_NOT_FOUND);    }    /**     * 增加item类型     * @param type item类型     * @param layoutResId item布局文件     */    protected void addItemType(int type, @LayoutRes int layoutResId) {        if (layouts == null) {            layouts = new SparseIntArray();        }        layouts.put(type, layoutResId);    }}
  1. 首先我们用SparseIntArray来存储不同的type所对应的布局
  2. 然后因为实体类都是实现了getItemType()方法的,我们在判断item类型时(getDefItemViewType()),直接调用子类的getItemType()方法即可知道该item的type.
  3. 在adapter的onCreateViewHolder()的时候,onCreateDefViewHolder()方法里通过type从SparseIntArray中获取布局id.
  4. 外部实现adapter的时候直接调用addItemType()方法即可添加新的类型和该类型对应的布局,其实就是将该(key,value)插入到了SparseIntArray中,需要用的时候再拿出来

总结

其实实现了BaseQuickAdapter,再来加入一个多布局,其实很简单.
就是多添加几种type,然后每一种type对应一种布局.
让实体类自己去实现一个getItemType()方法,然后adapter这边才知道该item是什么type,然后加载什么布局.

当然,实现多布局的方式多种多样,开源库中还提供了一种:https://github.com/CymChad/BaseRecyclerViewAdapterHelper/issues/968

其实都是大同小异的,喜欢哪种方式,就用哪种方式.

阅读全文
0 0
原创粉丝点击