美文网首页androidAndroid开发Android开发经验谈
(再次更新)打造RecyclerView万能适配器,上拉刷新,下

(再次更新)打造RecyclerView万能适配器,上拉刷新,下

作者: 极客简讯 | 来源:发表于2017-11-30 10:08 被阅读184次

    入行几个月了,一直想自己封装一些类,刚好遇到了这个问题,现在跟大家分享。
    注意点
    1 泛型擦除
    2 需要防止类型转换异常
    github地址:https://github.com/zw21544182/MyBaseDemo
    (里面还有部分FileUtils常用相关方法),欢迎start 一起交流进步
    关于RecyclerView.Adapter 一般的套路是这个样子的

    public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {
        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            //创建ViewHolder
            return null;
        }
    
        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
        //绑定数据
        }
    
        @Override
        public int getItemCount() {
            //获取数据行数
            return 0;
        }
    
        public class ViewHolder extends RecyclerView.ViewHolder {
            public ViewHolder(View itemView) {
                //绑定Itme 中的View
                super(itemView);
            }
        }
    }
    

    现在我想写一个Adapter的基类
    最初的想法是指定一个泛型,像这样

    public class MyRecyclerViewAdapter<T> extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {
        List<T> data;
        Context context;
        int layoutId;
    
        public MyRecyclerViewAdapter(List<T> data, Context context, int layoutId) {
            this.data = new ArrayList<>();
            data.addAll(data);
            this.context = context;
            this.layoutId = layoutId;
        }
    
        //添加一些 setData clearData等方法
        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            //创建ViewHolder
            View view = LayoutInflater.from(this.context).inflate(this.layoutId, parent, false);
            return new ViewHolder(view);
        }
    
        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            //绑定数据
        }
    
        @Override
        public int getItemCount() {
            //获取数据行数
            return data.size();
        }
    
        public class ViewHolder extends RecyclerView.ViewHolder {
            public ViewHolder(View itemView) {
                //绑定Itme 中的View
                super(itemView);
            }
        }
    }
    

    自我感觉这样很完美,但是编译通不过。报没有实现子类onBindViewHolder的错,额,好吧。就这样,尴尬了一会,在网上查了查资料。后来想到为什么不直接泛型擦除呢?
    最后就有了现在这个BaseRecyclerAdapter

    /**
     * 创建时间: 2017/11/29
     * 创建人: Administrator
     * 功能描述:RecyclerView基类(需要注意类型转换问题)
     */
    public abstract class BaseRecyclerViewAdapter extends RecyclerView.Adapter<BaseRecyclerViewAdapter.BaseViewHolder> {
        protected ArrayList data;
        protected Context context;
        protected List<Integer> layoutIds;//布局集合
        protected boolean isMore = true;//上拉刷新时,是否有更多数据
    
        public BaseRecyclerViewAdapter(List data, Context context, List<Integer> layoutIds) {
            this.data = new ArrayList<>();
            this.layoutIds = new ArrayList<>();
            this.data.addAll(data);
            this.layoutIds.addAll(layoutIds);
            this.context = context;
        }
    
        public void setData(List data) {
            this.data.clear();
            this.data.addAll(data);
            notifyDataSetChanged();
        }
    
        public void clearAll() {
            this.data.clear();
            notifyDataSetChanged();
        }
    
        public Object getDataByPos(int index) {
            if (data.size() <= index) {
                return null;
            }
            return data.get(index);
        }
    
        public void addData(Object t) {
            data.add(t);
            notifyDataSetChanged();
        }
    
        public void addDatas(List data) {
            this.data.addAll(data);
            notifyDataSetChanged();
        }
    #重要 设置viewType
        @Override
        public int getItemViewType(int position) {
            if (position + 1 == getItemCount()) {
                return -1;//最后行时设为-1显示footLayout
            } else {
                return position;//其他设为位置
            }
    
        }
    
        @Override
        public BaseViewHolder onCreateViewHolder(ViewGroup parent, int pos) {
            if (data.size() == 0) {//当data数据为0时
                View view = LayoutInflater.from(context).inflate(R.layout.zwbase_no_data, parent, false);
                //显示暂无数据布局
                return new BaseViewHolder(view);
            }
            if (pos == -1) {//pos为-1表示最后一行 
                View view = LayoutInflater.from(context).inflate(R.layout.zwbase_footlayout, parent, false);
                //显示底部布局
                return new FootViewHolder(view);
            }
            int layout = getLayoutIdByPos(pos);
            View view = LayoutInflater.from(context).inflate(layout, parent, false);
            BaseViewHolder baseViewHolder = new BaseViewHolder(view);
            clickView(baseViewHolder, data.get(pos), pos);
            return baseViewHolder;
        }
    
        protected int getLayoutIdByPos(int pos) {
            int res = 0;
            if (pos < layoutIds.size()) {//layoutIds是存放布局的集合
                res = layoutIds.get(pos);
            } else {
                res = layoutIds.get(pos % layoutIds.size());
            }
            return res;
        }
    
    
        /**
         * 在oncreateViewHolder方法中设置点击事件
         * 避免重复调用
         * @param baseViewHolder itme控件
         * @param o              itme    实体类
         * @param pos            位置
         */
        protected abstract void clickView(BaseViewHolder baseViewHolder, Object o, int pos);
    
        protected abstract void setItmeData(BaseViewHolder baseViewHolder, Object itmeModule, int position) throws ClassCastException;
    
        @Override
        public void onBindViewHolder(BaseViewHolder holder, int position) {
            if (data.size() == 0) {
                ImageView nodataImage = (ImageView) holder.getViewById(R.id.zwbase_imageview);
                TextView nodataText = (TextView) holder.getViewById(R.id.zwbase_tvNoData);
                setNodataInfo(nodataImage, nodataText);
                return;
            }
            if (holder instanceof FootViewHolder) {
                //判断为底部布局时
                if (isMore) {//再次判断是否还有更多数据,加载相应的布局
                    holder.getViewById(R.id.loadmore).setVisibility(View.VISIBLE);
                    holder.getViewById(R.id.nodata).setVisibility(View.GONE);
                } else {
                    holder.getViewById(R.id.loadmore).setVisibility(View.GONE);
                    holder.getViewById(R.id.nodata).setVisibility(View.VISIBLE);
                }
                return;
            }
            try {
                setItmeData(holder, data.get(position), position);//设置显示数据
            } catch (ClassCastException e) {
                e.printStackTrace();
            }
        }
    
        protected void setNodataInfo(ImageView nodataImage, TextView nodataText) {
        }
    
    
        @Override
        public int getItemCount() {
            return data == null ? 0 : data.size() + 1;//数据为0或为空时返回0,否则data.size()+1
        }
    
        public void setMore(boolean more) {
            //暴露方法给Activity
            this.isMore = more;
        }
    
        protected class FootViewHolder extends BaseViewHolder {
            public FootViewHolder(View itemView) {
                super(itemView);
            }
        }
    
        public class BaseViewHolder extends RecyclerView.ViewHolder {
            //该类下部分方法可以自行添加
            View rootView;
    
            public BaseViewHolder(View itemView) {
                super(itemView);
                rootView = itemView;
            }
    
            public void setText(int viewId, int resourceId) {
                ((TextView) getViewById(viewId)).setText(resourceId);
            }
    
            public void setClickListent(int viewId, View.OnClickListener onClickListener) {
                getViewById(viewId).setOnClickListener(onClickListener);
            }
    
            public void setText(int viewId, String content) {
                ((TextView) getViewById(viewId)).setText(content);
            }
    
            public void setCheckChangeListen(int viewId, CompoundButton.OnCheckedChangeListener onCheckedChangeListener) {
                ((CheckBox) getViewById(viewId)).setOnCheckedChangeListener(onCheckedChangeListener);
            }
    
            public void setImageSource(int imageViewId, int sourceId) {
                ImageView imageView = (ImageView) getViewById(imageViewId);
                imageView.setImageResource(sourceId);
            }
    
            public View getViewById(int viewId) {
                return rootView.findViewById(viewId);
            }
        }
    }
    

    在打造我们自己的适配器时,我们可以继承BaseRecyclerViewAdaPter

    public class MyAdapter extends BaseRecyclerViewAdapter {
    
        public MyAdapter(List data, Context context, List<Integer> layoutIds) {
            super(data, context, layoutIds);
        }
    
        @Override
        protected void clickView(BaseViewHolder baseViewHolder, Object o, int pos) {
    
        }
    
        @Override
        protected void setItmeData(BaseViewHolder baseViewHolder, Object itmeModule, int position) throws ClassCastException {
            int layoutNum = (position % layoutIds.size());
    
            switch (layoutNum) {
                case 0:
                    baseViewHolder.setText(R.id.tvText, (String) itmeModule);
                    break;
                case 1:
                    baseViewHolder.setImageSource(R.id.ivImage, R.mipmap.image);
                    break;
            }
        }
    }
    

    在activity中传入相关的布局Id号即可

      data = new ArrayList<>();
            layoutIds = new ArrayList<>();
            layoutIds.add(R.layout.layout_rvitme);
            layoutIds.add(R.layout.layout_image);
    //需要注意的是layoutIds传入的布局Id的顺序和个数要与Adapter中的setItmeData对应
            for (int i = 0; i < 100; i++) {
                data.add("sssss " + i);
            }
            baseRecyclerViewAdapter = new MyAdapter(data, this, layoutIds);
            myRview.setLayoutManager(new LinearLayoutManager(this));
            myRview.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
            myRview.setAdapter(baseRecyclerViewAdapter);
    

    最后, 花了一些时间,封装成了可刷新的view 下拉刷新用的官方+接口回调,上拉加载也是 可以去github上看看,一起交流学习

    相关文章

      网友评论

      • 君莫醉:增加了activity fragment的代码量,限制了RecyclerView多布局
        极客简讯:@君莫醉 itmeview的强转可以放到BasrViewHolder里去 再封装就行了 就像settext那个方法那样
        君莫醉:@掌上微科技 都是强转,感觉比泛型更麻烦了
        极客简讯:@君莫醉 不会限制多布局丫 要是多布局的话重写getViewType就好了啦 稍微改一下

      本文标题:(再次更新)打造RecyclerView万能适配器,上拉刷新,下

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