Android应用开发那些事

可展开Recyclerview适配器支持Header、Foote

2020-05-20  本文已影响0人  jerryhigh

前言

Android RecyclerView的适配器。面对各种列表的需求,急需要梳理一下,抽象出一个快速开发列表的适配器,减小代码量,提高开发效率。
可展开的Adapter支持的功能如下:

  • 支持两行可展开能力(单一类型适配)
  • 支持空状态;
  • 支持Header、Footer的适配
  • LoadMore的适配

使用类:BaseExpandableRecyclerViewAdapter
demo地址:

1. 用法

(1)基本可展开的group写法

public class SampleAdapter extends
        BaseExpandableRecyclerViewAdapter<SampleGroupBean, SampleChildBean, SampleAdapter.GroupVH, SampleAdapter.ChildVH> {

    private List<SampleGroupBean> mList;

    public SampleAdapter(List<SampleGroupBean> list) {
        mList = list;
    }

    @Override
    public int getGroupCount() {
        return mList.size();
    }

    @Override
    public SampleGroupBean getGroupItem(int position) {
        return mList.get(position);
    }

    @Override
    public GroupVH onCreateGroupViewHolder(ViewGroup parent, int groupViewType) {
        return new GroupVH(
                LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.listitem_group, parent, false));
    }

    @Override
    public ChildVH onCreateChildViewHolder(ViewGroup parent, int childViewType) {
        return new ChildVH(
                LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.listitem_child, parent, false));
    }

    @Override
    public void onBindGroupViewHolder(GroupVH holder, SampleGroupBean sampleGroupBean, boolean isExpanding) {
        holder.nameTv.setText(sampleGroupBean.getName());
        if (sampleGroupBean.isExpandable()) {
            holder.foldIv.setVisibility(View.VISIBLE);
            holder.foldIv.setImageResource(isExpanding ? R.drawable.ic_arrow_expanding : R.drawable.ic_arrow_folding);
        } else {
            holder.foldIv.setVisibility(View.INVISIBLE);
        }
    }

    @Override
    public void onBindChildViewHolder(ChildVH holder, SampleGroupBean groupBean, SampleChildBean sampleChildBean) {
        holder.nameTv.setText(sampleChildBean.getName());
    }

    static class GroupVH extends BaseExpandableRecyclerViewAdapter.BaseGroupViewHolder {
        ImageView foldIv;
        TextView nameTv;

        GroupVH(View itemView) {
            super(itemView);
            foldIv = (ImageView) itemView.findViewById(R.id.group_item_indicator);
            nameTv = (TextView) itemView.findViewById(R.id.group_item_name);
        }

        @Override
        protected void onExpandStatusChanged(RecyclerView.Adapter relatedAdapter, boolean isExpanding) {
            foldIv.setImageResource(isExpanding ? R.drawable.ic_arrow_expanding : R.drawable.ic_arrow_folding);
        }
    }

    static class ChildVH extends RecyclerView.ViewHolder {
        TextView nameTv;

        ChildVH(View itemView) {
            super(itemView);
            nameTv = (TextView) itemView.findViewById(R.id.child_item_name);
        }
    }

}

(2)支持Header、Footer写法

      adapter.setHeaderViewProducer(new ViewProducer() {
            @Override
            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
                return new DefaultEmptyViewHolder(
                        LayoutInflater.from(parent.getContext()).inflate(R.layout.header, parent, false)
                );
            }
            @Override
            public void onBindViewHolder(RecyclerView.ViewHolder holder) {
            }
        });
        adapter.setFooterViewProducer(new ViewProducer() {
            @Override
            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
                return new DefaultEmptyViewHolder(
                        LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_footview, parent, false)
                );
            }

            @Override
            public void onBindViewHolder(RecyclerView.ViewHolder holder) {
            }
        });

(3)支持EmptyView写法

      adapter.setEmptyViewProducer(new ViewProducer() {
            @Override
            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
                return new DefaultEmptyViewHolder(
                        LayoutInflater.from(parent.getContext()).inflate(R.layout.empty, parent, false)
                );
            }
            @Override
            public void onBindViewHolder(RecyclerView.ViewHolder holder) {
            }
        });

(4)支持LoadMore写法

       adapter.setLoadMoreProducer(new ViewProducer() {
            @Override
            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
                return new DefaultEmptyViewHolder(
                        LayoutInflater.from(parent.getContext()).inflate(R.layout.load_next_page, parent, false)
                );
            }
            @Override
            public void onBindViewHolder(RecyclerView.ViewHolder holder) {
            }
        });

(5)点击的监听

            adapter.setListener(new BaseExpandableRecyclerViewAdapter.ExpandableRecyclerViewOnClickListener<GroupBean,
                    SampleChildBean>() {
                @Override
                public boolean onGroupLongClicked(GroupBean groupItem) {
                    return false;
                }
                @Override
                public boolean onInterceptGroupExpandEvent(GroupBean groupItem, boolean isExpand) {
                    return false;
                }
                @Override
                public void onGroupClicked(GroupBean groupItem) {
                }
                @Override
                public void onChildClicked(GroupBean groupItem, SampleChildBean childItem) {
              }
            });

2. 基本原理

基本继承RecyclerView.Adapter复写的类中封装了一些常用到的写法,抽象出来

(1)在getItemViewType中分别对ViewType做区分:VIEW_TYPE_EMPTY > VIEW_TYPE_LOADMORE > VIEW_TYPE_FOOT > VIEW_TYPE_HEAD。其中将Group和Child也当作为一种类型进行区分,根据position、及group和child的数量可以计算出折叠或者展开之后的位置。
(2)抽象出getGroupCount、getGroupItem、onCreateGroupViewHolder、onBindGroupViewHolder
(3)抽象出onCreateChildViewHolder、onBindChildViewHolder
(4)抽象出BaseGroupBean,包含getChildCount、getChildAt、isExpandable方法
(5)在onCreateViewHolder中根据type进行创建不同的布局 ,并进行封装

switch (viewType & TYPE_MASK) {
            case TYPE_EMPTY:
                return mEmptyViewProducer.onCreateViewHolder(parent);
            case TYPE_HEADER:
                return mHeaderViewProducer.onCreateViewHolder(parent);
            case TYPE_FOOTER:
                return mFooterViewProducer.onCreateViewHolder(parent);
            case TYPE_LOAD_MORE:
                return mLoadMoreViewProducer.onCreateViewHolder(parent);
            case TYPE_CHILD:
                return onCreateChildViewHolder(parent, viewType ^ TYPE_CHILD);
            case TYPE_GROUP:
                return onCreateGroupViewHolder(parent, viewType ^ TYPE_GROUP);
            default:
                throw new IllegalStateException(
                        String.format(Locale.getDefault(), "Illegal view type : viewType[%d]", viewType));

        }

(6)在getItemCount中将几个类型的布局数量算进去
(7)在onBindViewHolder中进行实际数据绑定的封装。

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List<Object> payloads) {
        switch (holder.getItemViewType() & TYPE_MASK) {
            case TYPE_EMPTY:
                mEmptyViewProducer.onBindViewHolder(holder);
                break;
            case TYPE_HEADER:
                mHeaderViewProducer.onBindViewHolder(holder);
                break;
            case TYPE_FOOTER:
                mFooterViewProducer.onBindViewHolder(holder);
                break;
            case TYPE_LOAD_MORE:
                mLoadMoreViewProducer.onBindViewHolder(holder);
                if (mOnLoadMoreListener != null) {
                    mOnLoadMoreListener.onLoadMoreRequested();
                }
                break;
            case TYPE_CHILD:
                final int[] childCoord = translateToDoubleIndex(position);
                GroupBean groupBean = getGroupItem(childCoord[0]);
                bindChildViewHolder((ChildViewHolder) holder, groupBean, groupBean.getChildAt(childCoord[1]), payloads);
                break;
            case TYPE_GROUP:
                bindGroupViewHolder((GroupViewHolder) holder, getGroupItem(translateToDoubleIndex(position)[0]), payloads);
                break;
            default:
                throw new IllegalStateException(
                        String.format(Locale.getDefault(), "Illegal view type : position [%d] ,itemViewType[%d]", position, holder.getItemViewType()));
        }
    }

3. 持续迭代

  • 多种类型适配
  • 支持grid
  • 支持stickyHead

4. 效果图

效果图
上一篇下一篇

猜你喜欢

热点阅读