学习MultiViewAdapter——1

来源:互联网 发布:php魔术方法isset() 编辑:程序博客网 时间:2024/05/29 19:27

本文讲到的关于MultiViewAdapter,是学习国外牛人在GitHub上的开源项目。具体的使用方法可以看Wiki。


项目中我们会经常用到RecyclerView实现多种效果,这里简单提一下那几个方法。

  • getItemViewType()返回item的视图类型,默认返回的是0.与ListView适配器不同,视图类型不需要连续不断。可以考虑使用id来识别项视图类型。
  • onCreateViewHolder()根据不同类型的item来创建不同类型的viewholder
  • onBindViewHolder()根据不同类型的viewholder来绑定不同的数据

还有一些方法这里就不提了,基本上的模板代码就是那样。
例如:

public class CustomAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {    private static final String TAG = "CustomAdapter";    private Context context;    private LayoutInflater inflater;    private List<JavaBean> items = new ArrayList<>();    public CustomAdapter(Context context){        this.context = context;        inflater = LayoutInflater.from(context);    }    @Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        if (viewType == JavaBean.TYPE_A) {            View view = inflater.inflate(R.layout.item_chat_right, parent, false);            AHolder aHolder = new AHolder(view);            return aHolder;        }else if (viewType == JavaBean.TYPE_B){            View v = inflater.inflate(R.layout.item_chat_left,parent,false);            BHolder bHolder = new BHolder(v);            return bHolder;        }        return null;    }    @Override    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {        if (holder instanceof AHolder) {            AHolder aHolder = (AHolder) holder;            if (items != null) {                aHolder.tvChatContent.setText(items.get(position).getText());                aHolder.imgChatHead.setImageURI(Uri.parse(items.get(position).getHeadUrl()));            }        }else if (holder instanceof BHolder){            BHolder bHolder = (BHolder) holder;            if (items!=null){                bHolder.tvChatContent.setText(items.get(position).getText());            }        }    }    @Override    public int getItemCount() {        if (items!=null)            return items.size();        else            return 0;    }    @Override    public int getItemViewType(int position) {        return items.get(position).getType();    }    public void addMsg(ChatBean msg){        items.add(msg);        notifyItemInserted(items.size());    }    public class AHolder extends RecyclerView.ViewHolder {        private TextView tvChatContent;        private SimpleDraweeView imgChatHead;        public AHolder(View itemView) {            super(itemView);            tvChatContent = (TextView) itemView.findViewById(R.id.tv_chat_right);            imgChatHead = (SimpleDraweeView) itemView.findViewById(R.id.img_chat_head_right);        }    }    public class BHolder extends RecyclerView.ViewHolder {        private TextView tvChatContent;        private SimpleDraweeView imgChatHead;        public BHolder(View itemView) {            super(itemView);            tvChatContent = (TextView) itemView.findViewById(R.id.tv_chat_left);            imgChatHead = (SimpleDraweeView) itemView.findViewById(R.id.img_chat_head_left);        }    }}

看到了吧,如果使用常规的方式去写也是没有问题。像我之前实现了汽车上使用的WiFi列表,我都没有用RecyclerView直接一个ListView就搞定了,但是如果要有9-8种ViewType呢?你还敢这么写吗。所以说我们要么自己去封装库,要么上网用别人写好的。这里面有两个问题,第一种是自己写不来可扩展性强的库,没有那水平。第二种是用第三方的库,有了问题的话,如果不熟悉源码,那么有一个低概率的bug,只要是关于这个库的,基本上就没有办法解决。所以我们平时闲着的时候,要去多看看第三方库里面的源代码。这样以后有了问题,心就不虚了。


该库的作者在自己的博客中给出了一张图:
这里写图片描述

1.DataManger — 它持有数据而在数据修改的时候调用动画并且提供了DiffUtil的支持。有两种DataManager:显示list的DataListManager以及显示一个item(比如Header, Footer 等)的DataItemManager。

2.RecyclerAdapter继承了CoreRecyclerAdapter(处理数据),子类的适配器可以继承RecyclerAdapter,因为RecyclerAdapter可以持有多个 ItemBinder和DataManager来处理View与数据。

3.ItemBinder —ItemBinder的职责是创建和绑定viewholder。它提供了关于View的基础操作,例如:点击,长按,选择item的监听事件,它还有一个type参数,接收需要显示的model类。ItemBinder需要在子类实现RecyclerAdapter的类中注册。

我们先说一说ItemViewHolder

RecyclerView必须有一个ViewHolder,所以先对ViewHolder做了封装。

public class ItemViewHolder<M> extends RecyclerView.ViewHolder        implements View.OnClickListener, View.OnLongClickListener {    private M item;    private OnItemClickListener<M> itemClickListener;    private OnItemLongClickListener<M> itemLongClickListener;    private ItemActionListener actionListener;    public ItemViewHolder(View itemView) {        super(itemView);        itemView.setOnClickListener(this);        itemView.setOnLongClickListener(this);    }    @RestrictTo(RestrictTo.Scope.LIBRARY)    @Override    public final void onClick(View view) {        if (null == itemClickListener) return;        itemClickListener.onItemClick(view, getItem());    }    @RestrictTo(RestrictTo.Scope.LIBRARY)    @Override    public final boolean onLongClick(View view) {        return null != itemLongClickListener && itemLongClickListener.onItemLongClick(view, getItem());    }    final void setItemActionListener(ItemActionListener actionListener) {        this.actionListener = actionListener;    }    public final M getItem() {        return item;    }    ////////////////////////////////////////    ///////// Public Methods ///////////////    ////////////////////////////////////////    final void setItem(M item) {        this.item = item;    }    /**     * item选择     */    protected final void toggleItemSelection() {        actionListener.onItemSelectionToggled(getAdapterPosition());    }    /**     * item展开     */    protected final void toggleItemExpansion() {        actionListener.onItemExpansionToggled(getAdapterPosition());    }    /**     * 子视图可以调用 {@link DataGroupManager}'s来扩展     *     */    protected final void toggleGroupExpansion() {        actionListener.onGroupExpansionToggled(getAdapterPosition());    }    protected final void setItemClickListener(OnItemClickListener<M> itemClickListener) {        this.itemClickListener = itemClickListener;    }    protected final void setItemLongClickListener(OnItemLongClickListener<M> itemLongClickListener) {        this.itemLongClickListener = itemLongClickListener;    }    public final boolean isItemSelected() {        return actionListener.isItemSelected(getAdapterPosition());    }    public final boolean isItemExpanded() {        return actionListener.isItemExpanded(getAdapterPosition());    }    public final boolean isInActionMode() {        return actionListener.isAdapterInActionMode();    }    /**     * 返回ItemViewHolder的滑动方向。     * 默认返回0     * 这个方法可以被子类覆盖,可以提供有效的滑动方向标志。     *     * @return A binary OR of direction flags.     */    public int getSwipeDirections() {        return 0;    }    /**     * 返回ItemViewHolder的拖,拽动方向。     * 默认返回0     * 这个方法可以被子类覆盖,可以提供有效的滑动方向标志。     *     * @return A binary OR of direction flags.     */    public int getDragDirections() {        return 0;    }    /**     * 该方法允许用户开始拖拽viewholder     */    public final void startDrag() {        actionListener.onStartDrag(this);    }    public interface OnItemClickListener<M> {        void onItemClick(View view, M item);    }    public interface OnItemLongClickListener<M> {        boolean onItemLongClick(View view, M item);    }}

在ViewHolder中,定义了各种点击事件的监听,这样子类在实现点击事件的时候,在ViewHolder中实现就可以了。其中ItemActionListener定义了各种事件的监听。

接着我们看看上面提到的关于ItemBinder 

public abstract class ItemBinder<M, VH extends ItemViewHolder<M>> {    private List<ItemDecorator> itemDecorators;    public ItemBinder() {    }    public ItemBinder(ItemDecorator itemDecorator) {        addDecorator(itemDecorator);    }    public abstract VH create(LayoutInflater inflater, ViewGroup parent);    /**     * @param holder itemholder     *               给列表设置数据     * @param item   持有数据的对象     * @see #bind(ItemViewHolder, Object, List)     */    public abstract void bind(VH holder, M item);    /**     * @param item 持有数据的对象     */    public abstract boolean canBindData(Object item);    public void bind(VH holder, M item, List payloads) {        bind(holder, item);    }    public int getSpanSize(int maxSpanCount) {        return 1;    }    /**     * 添加分割线     */    public final void addDecorator(ItemDecorator itemDecorator) {        addDecorator(itemDecorator, -1);    }    public final void addDecorator(ItemDecorator itemDecorator, int priority) {        if (null == itemDecorators) {            itemDecorators = new ArrayList<>();        }        if (priority >= 0 && itemDecorators.size() > priority) {            itemDecorators.add(priority, itemDecorator);        } else {            itemDecorators.add(itemDecorator);        }    }    ///////////////////////////////////////////    /////////// Internal API ahead. ///////////    ///////////////////////////////////////////    void bindViewHolder(VH holder, M item) {        bind(holder, item);    }    void bindViewHolder(VH holder, M item, List payloads) {        bind(holder, item, payloads);    }    VH createViewHolder(LayoutInflater inflater, ViewGroup parent,                        ItemActionListener actionListener) {        VH viewHolder = create(inflater, parent);        viewHolder.setItemActionListener(actionListener);        return viewHolder;    }    boolean isItemDecorationEnabled() {        return itemDecorators != null;    }    void getItemOffsets(Rect outRect, int position, @PositionType int positionType) {        if (null == itemDecorators) {            return;        }        for (ItemDecorator itemDecorator : itemDecorators) {            itemDecorator.getItemOffsets(outRect, position, positionType);        }    }    void onDraw(Canvas canvas, RecyclerView parent, View child, int position,                @PositionType int positionType) {        if (null == itemDecorators) {            return;        }        for (ItemDecorator itemDecorator : itemDecorators) {            itemDecorator.onDraw(canvas, parent, child, position, positionType);        }    }}
  • 子类可以继承ItemBinder,并且将Mode数据放入泛型中
  • create(...)方法用来返回布局
  • bind方法用来设置数据
  • canBindData()这个方法很重要,我们需要确认item数据是否是Mode类的一个实例,这个方法我会在后面讲,他有什么用。
  • getSpanSize()有了这个也就是为你提供了更方便的跨列合并的方法
  • addDecorator 可以为你的ItemBinder添加分割线

    到了这里,已经将View布局已经分离出来了,正如作者说到的“ItemBinder的职责是创建和绑定视图” 。那么我将在下一篇介绍剩下的两个重要概念RecyclerAdapterDataManger


在工作中,如果打杂的任务做的太多了,时间太长了,那么你就真的是这家公司打杂的人了。后知后觉,每到升职加薪的时候,领导在问你工作专业性的时候,你就无话可说了。

原创粉丝点击