美文网首页
通用RecycleViewAdapter设计

通用RecycleViewAdapter设计

作者: Ggx的代码之旅 | 来源:发表于2018-12-13 15:52 被阅读12次

    本文章参考自:为RecyclerView打造通用Adapter 让RecyclerView更加好用

    设计步骤:

    1. 封装ViewHodler类
    2. 封装RecycleView.Adapter类,编写公共逻辑和方法。
    3. 进一步提升通用性,添加多Item类型支持

    封装ViewHolder

    每次写Adapter的时候总会依赖一个ViewHodler类,也是挺麻烦的事,虽说只要继承一下系统的ViewHolder但是如果控件比较多,那还是一种很苦恼的事。

    • 设计思路
      每个ViewHodler都需要依赖一个View,所有的子控件都是从这个View中获取。因此我们可以不必定义好那么多子控件,只需要用到的时候去拿就行。直接上代码:
    public final class RecycleViewHolder extends RecyclerView.ViewHolder {
    
        private SparseArray<View> views;
    
        private RecycleViewHolder(@NonNull View itemView) {
            super(itemView);
            views=new SparseArray<>();
        }
      
        /**
         * 创建ViewHolder
         * @param context 上下文
         * @param parent 父View
         * @param layoutId 布局Id
         * @return 返回ViewHolder
         */
        public static RecycleViewHolder get(@NonNull Context context,@NonNull ViewGroup parent,@LayoutRes int layoutId){
            View itemView=LayoutInflater.from(context).inflate(layoutId,parent,false);
            return new RecycleViewHolder(itemView);
    
        }
    
        public <T extends View>T getView(int id){
            View view=views.get(id);
            if(view==null){
                view=itemView.findViewById(id);
                views.put(id,view);
            }
            return (T) view;
        }
    
        public View getItemView() {
            return itemView;
        }
    }
    

    代码很少,直接看关键方法public <T extends View>T getView(int id),该方法负责从ItemView中获取子控件,控件只需要获取一次就好,因此这里加入了缓存SparseArray,如果已经存在就不再去findViewById了。

    封装RecycleView.Adapter类

    • 设计思路
      每个Adapter都需要依赖一个集合数据,以及Item布局和类型,还有它的ViewHolder,这些都是公共的。变化的只是在onBindViewHolder中的内容。
      1. 集合数据好弄,我们只需要利用泛型功能即可。
      2. Item布局和类型,利用接口,让使用者提供即可。
      3. ViewHolder就是我们上面封装的通用ViewHodler。
      4. onBindViewHolder中内容,抽象出来让使用者自己实现。
    public  class EasyRecyclerViewAdapter<T> extends RecyclerView.Adapter<RecycleViewHolder> {
    
    
        private Context mContext;
        private List<T> datas;
        private MutliItemType<T> mutliItemTypeSupport;
        private OnItemClickListener<T> onItemClickListener;
        private OnItemLongClickListener<T> onItemLongClickListener;
        private OnBindView<T> onBindView;
    
        /**
         * 单布局构造器
         * @param mContext 上下文
         * @param datas 数据集合
         * @param layoutId 布局Id
         */
        public EasyRecyclerViewAdapter(Context mContext, List<T> datas,@LayoutRes int layoutId) {
            this(mContext,datas,itemType -> layoutId);
        }
    
        /**
         * 多布局支持构造器
         * @param mContext 上下文
         * @param datas 集合数据
         * @param mutliItemTypeSupport {@link MutliItemType} 接口
         */
        public EasyRecyclerViewAdapter(Context mContext, List<T> datas, MutliItemType<T> mutliItemTypeSupport) {
            this(mContext,datas,mutliItemTypeSupport,null);
        }
    
        /**
         * 多布局支持构造器
         * @param mContext 上下文
         * @param datas 集合数据
         * @param mutliItemTypeSupport {@link MutliItemType} 接口
         * @param bindView {@link OnBindView}视图数据绑定接口
         */
        public EasyRecyclerViewAdapter(Context mContext, List<T> datas, MutliItemType<T> mutliItemTypeSupport,OnBindView<T> bindView) {
            this.mContext = mContext;
            this.datas = datas;
            this.mutliItemTypeSupport = mutliItemTypeSupport;
            this.onBindView=bindView;
        }
    
        @NonNull
        @Override
        public RecycleViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int itemType) {
            int layout=mutliItemTypeSupport.getLayout(itemType);
            return RecycleViewHolder.get(mContext,viewGroup,layout);
        }
    
        @Override
        public void onBindViewHolder(@NonNull RecycleViewHolder recycleViewHolder, int position) {
            T data=datas.get(position);
            if(onItemClickListener!=null){
                recycleViewHolder.getItemView().setOnClickListener(v ->
                        onItemClickListener.onItemClicked(recycleViewHolder,data,position));
            }
            if(onItemLongClickListener!=null){
                recycleViewHolder.getItemView().setOnLongClickListener(v ->
                        onItemLongClickListener.onItemLongClicked(recycleViewHolder,data,position));
            }
            if(onBindView!=null){
                onBindView.bind(recycleViewHolder,data,getItemViewType(position));
            }
        }
    
        @Override
        public int getItemCount() {
            return datas==null?0:datas.size();
        }
    
        @Override
        public int getItemViewType(int position) {
            return mutliItemTypeSupport.getItemViewType(position,datas==null?null:datas.get(position));
        }
    
        /*get/set ...*/
    
        public void setOnItemClickListener(OnItemClickListener<T> onItemClickListener) {
            this.onItemClickListener = onItemClickListener;
        }
    
        public OnItemClickListener<T> getOnItemClickListener() {
            return onItemClickListener;
        }
    
        public MutliItemType<T> getMutliItemTypeSupport() {
            return mutliItemTypeSupport;
        }
    
        public void setMutliItemTypeSupport(MutliItemType<T> mutliItemTypeSupport) {
            this.mutliItemTypeSupport = mutliItemTypeSupport;
        }
    
        public OnBindView<T> getOnBindView() {
            return onBindView;
        }
    
        public void setOnBindView(OnBindView<T> onBindView) {
            this.onBindView = onBindView;
        }
    
        public OnItemLongClickListener<T> getOnItemLongClickListener() {
            return onItemLongClickListener;
        }
    
        public void setOnItemLongClickListener(OnItemLongClickListener<T> onItemLongClickListener) {
            this.onItemLongClickListener = onItemLongClickListener;
        }
    
       /**
         * 多Item支持接口
         * @param <T>
         */
        public interface MutliItemType<T>{
    
            @LayoutRes int getLayout(int itemType);
    
            default int getItemViewType(int position,T data){
                return 0;
            }
        }
    
        public interface OnItemClickListener<T>{
            void onItemClicked(RecycleViewHolder holder,T data,int position);
        }
    
        public interface OnItemLongClickListener<T>{
            boolean onItemLongClicked(RecycleViewHolder holder,T data,int position);
        }
    
       /**
         * {@link this.onBindViewHolder} 转换接口,用来绑定自己的试图数据以及其他逻辑
         * @param <T>
         */
        public interface OnBindView<T>{
            void bind(RecycleViewHolder  holder,T data,int itemType);
        }
    }
    

    用过RecycleView的人对上面的代码一定不陌生。
    MutliItemType接口中定义了两个方法:

    1. @LayoutRes int getLayout(int itemType);
      该方法用来确布局定Layout
    2. default int getItemViewType(int position,T data)
      该方法用来确定item类型
      有了这个接口剩下的事就好办多了。重写父类的onCreateViewHoldergetItemViewType方法。
      onCreateViewHolder
      该方法用来确定ViewHodler,在上面的实现中一目了然,通过MutliItemType接口,获取LayoutId,然后使用通用ViewHodler 去创建出来。
      getItemViewType
      该方法用来告诉RecycleView当前是哪个Item类型。
      如次我们就能知道该创建那个布局,该绑定那个ViewHodler。

    相关文章

      网友评论

          本文标题:通用RecycleViewAdapter设计

          本文链接:https://www.haomeiwen.com/subject/xifbhqtx.html