美文网首页Android
Android 一起来封装一个RecyclerViewAdapt

Android 一起来封装一个RecyclerViewAdapt

作者: neverwoods | 来源:发表于2016-08-31 16:38 被阅读0次

    前言

    上一篇我们一起封装了一个还算简单实用的 Adapter,可惜是 ListView、GridView 用的。在 RecyclerView 大行其道的如今,对应 Adapter 的使用简单也是一个必然的需求。

    正文

    按照惯例,先来看看一个原始的 RecyclerViewAdapter 是怎么写的

    RecyclerView.Adapter adapter = new RecyclerView.Adapter() {
                @Override
                public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                    View itemView = LayoutInflater.from(context).inflate(layoutId, parent, false);
                    return new Holder(itemView);
                }
    
                @Override
                public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
                    Holder holder = (Holder) viewHolder;
    
                    holder.textView.setText(dataSource.get(position));
                    holder.button.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            //TODO
                        }
                    });
                }
    
                @Override
                public int getItemCount() {
                    return dataSource.size();
                }
            };
    
    private class Holder extends RecyclerView.ViewHolder {
    
            public TextView textView;
            public Button button;
    
            public Holder(View itemView) {
                super(itemView);
                textView = itemView.findViewById(textViewId);
                button = itemView.findViewById(buttonId);
            }
        }
    

    以上代码纯属盲打,如有错误敬请谅解。

    大致上我们能看到,相对于 ListView,RecyclerView 帮我们实现了 Item 的复用逻辑,不需要我们再写,但还是每次都要写一个 ViewHolder 类。之前我们是调用一个自己写的静态 ViewHolder 类,但是 RecyclerView 需要的 ViewHolder 一定是 RecyclerView.ViewHolder 或其子类,所以我们只能继承 RecyclerView.ViewHolder 来做封装工作。

    public class RecyclerViewHolder extends RecyclerView.ViewHolder {
    
        public RecyclerViewHolder(View itemView) {
            super(itemView);
        }
    
        public <T extends View> T getChildView(int id) {
            return (T) itemView.findViewById(id);
        }
    }
    

    其实只是添加了一个 getChildView 的方法用来获取子 View 而已。

    Adapter 的封装也很简单,只是添加了一个绑定数据的抽象方法:

    public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<RecyclerViewHolder> {
    
        /**
         * 由子类实现绑定方法
         * @param holder
         * @param data
         * @param position
         */
        protected abstract void onBindData(RecyclerViewHolder holder, T data, int position);
    
        protected Context mContext;
        protected List<T> mData;
        protected LayoutInflater mInflater;
        protected int layoutRes;
    
        public RecyclerAdapter(Context context, List<T> data, int layoutRes) {
            this.mData = data;
            this.mContext = context;
            this.layoutRes = layoutRes;
            this.mInflater = LayoutInflater.from(mContext);
        }
    
        public void refresh(List<T> data) {
            try {
                this.mData = data;
                notifyDataSetChanged();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            return new RecyclerViewHolder(mInflater.inflate(layoutRes, parent, false));
        }
    
        @Override
        public void onBindViewHolder(RecyclerViewHolder holder, int position) {
            onBindData(holder, mData.get(position), position);
        }
    
        @Override
        public int getItemCount() {
            return mData.size();
        }
    }
    

    我们来看看现在使用起来方不方便?

    RecyclerAdapter adapter = new RecyclerAdapter<String>(this, dataSource, layoutRes) {
                @Override
                protected void onBindData(RecyclerViewHolder holder, String data, int position) {
                    TextView textView = holder.getChildView(textViewId);
                    Button button = holder.getChildView(buttonId);
                    
                    textView.setText(data);
                    button.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            //TODO
                        }
                    });
                }
            };
    

    有木有一种很亲切的感觉?终于又回到了一个方法实现 Adapter 的日子了 T_T ~~

    小结

    封装之后才发现,其实 RecyclerView 的 Adapter 是可以封装得比 ListView 更为简洁易用的,这应该归功于 RecyclerView 自身就实现了缓存复用。

    真·正文

    还记得上一篇文章我就说过这还不是极简吗?仔细看上面的代码,每次重写绑定方法的时候,几乎都要先用 holder 的 getChild 方法获取到 view 实例,再进行填充数据、添加监听等操作。有没有一种办法能一步到位呢?

    当然有!

    先看代码

    public class RecyclerViewHolder extends RecyclerView.ViewHolder {
    
        public RecyclerViewHolder(View itemView) {
            super(itemView);
        }
    
        public <T extends View> T getChildView(int id) {
            return (T) itemView.findViewById(id);
        }
    
        public RecyclerViewHolder setText(int viewId, CharSequence charSequence) {
            TextView textView = getChildView(viewId);
            textView.setText(charSequence);
            return this;
        }
        ......
    }
    

    可以看出,我们给 ViewHolder 添加了 setText 方法,传入了 viewId 和我们想要设置的值,在方法内部去 getChildView 并进行了数据填充。同样的,设置监听等方法也可以这样子去实现。

    RecyclerAdapter adapter = new RecyclerAdapter<String>(this, dataSource, layoutRes) {
                @Override
                protected void onBindData(RecyclerViewHolder holder, String data, int position) {
                    holder.setText(textViewId, data)
                            .setOnClickListener(buttonId, new View.OnClickListener() {
                                @Override
                                public void onClick(View v) {
                                    //TODO
                                }
                            });
                }
            };
    

    再安利一下 lambda 表达式

    RecyclerAdapter adapter = new RecyclerAdapter<String>(this, dataSource, layoutRes) {
                @Override
                protected void onBindData(RecyclerViewHolder holder, String data, int position) {
                    holder.setText(textViewId, data)
                            .setOnClickListener(buttonId, (v) -> {/** TODO */});
                }
            };
    

    是不是感觉棒棒哒?很多常用的方法都可以放到 ViewHolder 中去,比如 setTextSize、setTextColor、setVisibility、setImageResource、setBackgroundColor 等。

    因为篇幅的关系,原本计划一起写的 ItemType 处理很难再塞进来。再加上 databinding 模式下的 Adapter 封装,感觉 Adapter 这个系列就够我写好一阵了,会不会有点狗血?

    感谢

    鸿扬大神:https://github.com/hongyangAndroid/baseAdapter
    以及我自己的开源项目:https://github.com/neverwoodsS/zy-open

    相关文章

      网友评论

        本文标题:Android 一起来封装一个RecyclerViewAdapt

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