美文网首页
RecyclerView系列(二)打造万能Adapter

RecyclerView系列(二)打造万能Adapter

作者: Ayres | 来源:发表于2017-07-19 14:40 被阅读0次

    我相信在写RecyclerView的Adapter时都感到有一点繁琐,有没有像ListView一样也能自定义一个万能的Adapter,答案是肯定的下面我们就来一步一步实现。

    一、基本实现

    要实现通用,我们无非要解决三个问题:
    1.数据
    2.布局
    3.绑定
    只有解决了这三个问题,才能基本实现,那么基本解决方法是:
    数据我们采用泛型,布局直接构造中传递,绑定显示效果就使用回传。
    如下:

    public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter<ViewHolder> {
    protected Context mContext;
    protected LayoutInflater mInflater;
    //数据
    protected List<T> mDatas;
    // 布局
    private int mLayoutId;
    public CommonRecyclerAdapter(Context context, List<T> datas, int layoutId) {
        this.mContext = context;
        this.mInflater = LayoutInflater.from(mContext);
        this.mDatas = datas;
        this.mLayoutId = layoutId;
    }
    
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // inflate数据
        View itemView = mInflater.inflate(mLayoutId, parent, false);
        // 返回ViewHolder
        ViewHolder holder = new ViewHolder(itemView);
        return holder;
    }
    
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        // 绑定回传
        convert(holder, mDatas.get(position));
    }
    
    /**
     * 利用抽象方法回传出去,每个不一样的Adapter去设置
     * @param item 当前的数据
     */
    public abstract void convert(ViewHolder holder, T item);
    
    @Override
    public int getItemCount() {
        return mDatas.size();
    }
    

    }

    二、基本使用

    解决了以上三个问题,我们来使用一下

    public class SimpleListAdapter extends BaseRecyclerAdapter<StringBean>{
     public SimpleListAdapter (Context context, List<StringBean> datas) {
        super(context, datas, R.layout.channel_list_item);
      }
    @Override
    public void convert(ViewHolder holder, StringBean  item) {
        // 从ViewHolder中去findViewById
        TextView nameTv = (TextView) holder.itemView.findViewById(R.id.channel_text);
    
        // 显示数据
        nameTv.setText(item.getName());
    }
    }
    

    三、进阶封装

    ViewHolder可以进一步改造,让convert方法简洁化,创建链式调用

    public class ViewHolder extends RecyclerView.ViewHolder {
    // 用来存放子View减少findViewById的次数
    private SparseArray<View> mViews;
    
    public ViewHolder(View itemView) {
        super(itemView);
        mViews = new SparseArray<>();
    }
    
    /**
     * 设置TextView文本
     */
    public ViewHolder setText(int viewId, CharSequence text) {
        TextView tv = getView(viewId);
        tv.setText(text);
        return this;
    }
    
    /**
     * 通过id获取view
     */
    public <T extends View> T getView(int viewId) {
        // 先从缓存中找
        View view = mViews.get(viewId);
        if (view == null) {
            // 直接从ItemView中找
            view = itemView.findViewById(viewId);
            mViews.put(viewId, view);
        }
        return (T) view;
    }
    
    /**
     * 设置View的Visibility
     */
    public ViewHolder setViewVisibility(int viewId, int visibility) {
        getView(viewId).setVisibility(visibility);
        return this;
    }
    
    /**
     * 设置ImageView的资源
     */
    public ViewHolder setImageResource(int viewId, int resourceId) {
        ImageView imageView = getView(viewId);
        imageView.setImageResource(resourceId);
        return this;
    }
    
    /**
     * 设置条目点击事件
     */
    public void setOnIntemClickListener(View.OnClickListener listener) {
        itemView.setOnClickListener(listener);
    }
    
    /**
     * 设置条目长按事件
     */
    public void setOnIntemLongClickListener(View.OnLongClickListener listener) {
        itemView.setOnLongClickListener(listener);
    }
    
    /**
     * 设置图片通过路径,这里稍微处理得复杂一些,因为考虑加载图片的第三方可能不太一样
     * 也可以直接写死
     */
    public ViewHolder setImageByUrl(int viewId, HolderImageLoader imageLoader) {
        ImageView imageView = getView(viewId);
        if (imageLoader == null) {
            throw new NullPointerException("imageLoader is null!");
        }
        imageLoader.displayImage(imageView.getContext(), imageView, imageLoader.getImagePath());
        return this;
    }
    
    /**
     * 图片加载,这里稍微处理得复杂一些,因为考虑加载图片的第三方可能不太一样
     * 也可以不写这个类
     */
    public static abstract class HolderImageLoader {
        private String mImagePath;
    
        public HolderImageLoader(String imagePath) {
            this.mImagePath = imagePath;
        }
    
        public String getImagePath() {
            return mImagePath;
        }
        public abstract void displayImage(Context context, ImageView imageView, String imagePath);
    }
    }
    

    四、进阶使用

     @Override
      public void convert(ViewHolder holder, StringBean   item) {
        // 显示数据
        holder.setText(R.id.channel_text, item.getName())
                .setText(R.id.channel_topic, item.getIntro())
                .setText(R.id.channel_update_info,item.getId());
        // 加载图片
        holder.setImageByUrl(R.id.channel_icon, new GlideImageLoader(item.getIcon_url()));
    }
    

    五、终级封装

    有的时候我们列表的样式各不相同,那么该怎么办呢,上面的封装就不能满足我们的要求。所以我们进一步封装,介绍RecyclerView.Adapter的getItemViewType(int position)这个方法,可以根据当前位置获取一个viewType最终会传到onCreateViewHolder()这个方法中。

      public interface MultiTypeSupport<T> {
        // 根据当前位置或者条目数据返回布局
      public int getLayoutId(T item, int position);
      }
    

    六、最终实现

    public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter<ViewHolder> {

    protected Context mContext;
    protected LayoutInflater mInflater;
    //数据
    protected List<T> mData;
    // 布局
    private int mLayoutId;
    // 多布局支持
    private MultiTypeSupport mMultiTypeSupport;
    
    public CommonRecyclerAdapter(Context context, List<T> data, int layoutId) {
        this.mContext = context;
        this.mInflater = LayoutInflater.from(mContext);
        this.mData = data;
        this.mLayoutId = layoutId;
    }
    
    /**
     * 多布局支持
     */
    public CommonRecyclerAdapter(Context context, List<T> data, MultiTypeSupport<T> multiTypeSupport) {
        this(context, data, -1);
        this.mMultiTypeSupport = multiTypeSupport;
    }
    
    /**
     * 根据当前位置获取不同的viewType
     */
    @Override
    public int getItemViewType(int position) {
        // 多布局支持
        if (mMultiTypeSupport != null) {
            return mMultiTypeSupport.getLayoutId(mData.get(position), position);
        }
        return super.getItemViewType(position);
    }
    
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // 多布局支持
        if (mMultiTypeSupport != null) {
            mLayoutId = viewType;
        }
        // inflate数据
        View itemView = mInflater.inflate(mLayoutId, parent, false);
        // 返ViewHolder
        ViewHolder holder = new ViewHolder(itemView);
        return holder;
    }
    
    @Override
    public void onBindViewHolder(ViewHolder holder, final int position) {
        // 设置点击和长按事件
        if (mItemClickListener != null) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mItemClickListener.onItemClick(position);
                }
            });
        }
        if (mLongClickListener != null) {
            holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    return mLongClickListener.onLongClick(position);
                }
            });
        }
    
        // 绑定回传
        convert(holder, mData.get(position));
    }
    
    /**
     * 利用抽象方法回传出去,每个不一样的Adapter去设置
     *
     * @param item 当前的数据
     */
    public abstract void convert(ViewHolder holder, T item);
    
    @Override
    public int getItemCount() {
        return mData.size();
    }
    
    /*
     * 设置条目点击和长按事件
     */
    public OnItemClickListener mItemClickListener;
    public OnLongClickListener mLongClickListener;
    
    public void setOnItemClickListener(OnItemClickListener itemClickListener) {
        this.mItemClickListener = itemClickListener;
    }
    
    public void setOnLongClickListener(OnLongClickListener longClickListener) {
        this.mLongClickListener = longClickListener;
    }
    }
    
    Paste_Image.png

    相关文章

      网友评论

          本文标题:RecyclerView系列(二)打造万能Adapter

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