Recycleview之打造通用的Adapter

概述

Recycleview 是安卓当今最常用的列表,封装一个比较简便的Adapter使代码更简便更易懂,将方法封装使用只关系数据变化才是王道
废话少说直接封装BaseAdapter

1.简单BaseAdapter的实现

在继承 RecyclerView.Adapter 后 会自动生成 onCreateViewHolder、onBindViewHolder、getItemCount 方法
onCreateViewHolder 是绑定布局, onBindViewHolder绑定数据,getItemCount是返回条数

首先我们要实现adapter的初始化我们需要构造方法

 /*简单初始化*/
    private int mLayoutId;//布局Id
   	private LayoutInflater mLayoutInflater;//初始化LayoutInflater 方便onCreateViewHolder初始化View
    public BaseAdapter(Context context, List<T> data, int layoutId) {
        this.mContext = context;
        this.mData = data;
        this.mLayoutId = layoutId;
        this.mLayoutInflater = LayoutInflater.from(context);
    }

接下来我们要完成onCreateViewHolder方法进行布局的绑定
这是我们需要ViewHolder来处理View的事件

  @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (mLayoutId == -1)
            throw new Resources.NotFoundException("没有找到该mLayoutId");
        View view = mLayoutInflater.inflate(mLayoutId, parent, false);
//       创建ViewHolder
        mViewHolder = new ViewHolder(view);
        return mViewHolder;
    }

所以我们在外边创建一个ViewHolder减少adapter里面的方法更简洁

public class ViewHolder extends RecyclerView.ViewHolder {
//    缓存View 选择性能更好的SparseArray 代替HashMap
    private SparseArray <WeakReference<View>> mViews;
    //初始化
    public ViewHolder(@NonNull View itemView) {
        super(itemView);
        mViews = new SparseArray<>();
    }
    
    //获取View 如果没有就添加缓存,有的话直接取
   public <T extends View> T getView(int viewId){
        WeakReference<View> view =  mViews.get(viewId);
        View view1 = null;
        if (view!=null){
             view1 = view.get();
        }else {
            view1 = itemView.findViewById(viewId);
            mViews.put(viewId,new WeakReference<View>(view1));
        }
        return (T) view1;
    }
//  链式调用设置文字 直接使用id来进行设置更清晰
    public ViewHolder setText (int viewId ,CharSequence charSequence){
        TextView view = getView(viewId);
        if (view==null){
            throw new InflateException("设置文字时没有找到该View");
        }else {
            view.setText(charSequence);
        }
        return  this;
    }
//    加载本地图片
    public ViewHolder setImageView (int viewId ,int resId){
        ImageView view = getView(viewId);
        if (view==null){
            throw new InflateException("设置图片时没有找到该View");
        }else {
            view.setImageResource(resId);
        }
        return  this;
    }
//    加载网络图片 ---》 创建了ImageLoader 接口 为了实现能使用各种三方库加载网络图片
    public ViewHolder setImageView (int viewId ,String url,ImageLoader imageLoader){
        ImageView view = getView(viewId);
        if (view==null){
            throw new InflateException("设置图片时没有找到该View");
        }else {
            imageLoader.loadImage(view,url);
        }
        return  this;
    }
//   onBindViewHolder方法内实现点击事件
    public void setOnItemClick(int viewId, final OnItemClick onItemClick){
        View view = getView(viewId);
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onItemClick.click(v);
            }
        });
    }
    //   onBindViewHolder方法内实现长按点击事件
    public void setOnLongItemClick(int viewId, final OnLongItemClick onLongItemClick){
        View view = getView(viewId);
        view.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                onLongItemClick.click(v);
                return true;
            }
        });
    }

//  接口 扩展使用各种网络图片的使用

    public interface ImageLoader{
        void  loadImage(ImageView imageView ,String url);
    }

}

ViewHolder 实现了view的一些基础功能
回到BaseAdapter中

   @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        bindViewHolder(holder, mData.get(position), position);
    }
    
    /*实现bindViewHolder方法*/
    protected abstract void bindViewHolder(ViewHolder holder, T t, int position);

我们将bindviewHolder方法在自己复写的Adapter中实现
同时我们将viewHolder 实体类T,以及位置信息全部传回adpter中进行界面的渲染
getItemCount肯定是返回传过来的数据

 private List<T> mData;
 @Override
    public int getItemCount() {
        return mData.size();
    }

其中为了适配在Activity中可能需要实现adpter的点击事件的问题我在BaseAdapter中添加了接口

/**
 * @author li
 * 版本:1.0
 * 创建日期:2020/6/8 09
 * 描述:onBindViewHolder方法内实现点击事件
 */
public interface OnItemClick {
    void click(View view);
}

/**
 * @author li
 * 版本:1.0
 * 创建日期:2020/6/8 09
 * 描述:onBindViewHolder方法内实现长按点击事件
 */
public interface OnLongItemClick {
    void click(View view);
}

/**
 * @author li
 * 版本:1.0
 * 创建日期:2020/6/8 09
 * 描述:activity内实现点击事件
 */
public interface AdapterOnItemClick<T> {
    void click(View view,T t,int type ,int pos);
}

/**
 * @author li
 * 版本:1.0
 * 创建日期:2020/6/8 09
 * 描述:activity内实现长按点击事件
 */
public interface AdapterOnLongItemClick<T> {
    void click(View view, T t, int type, int pos);
}

在Adpter中进行绑定接口

  //   初始化Adapter的点击事件 为了避免adapter中实现activity的点击事件在activity中没有实现造成闪退问题
    private AdapterOnItemClick<T> mAdapterOnItemClick = new AdapterOnItemClick<T>() {
        @Override
        public void click(View view, T t, int type, int pos) {
        }
    };
    //   初始化Adapter的长按点击事件
    private AdapterOnLongItemClick<T> mAdapterOnLongItemClick = new AdapterOnLongItemClick<T>() {
        @Override
        public void click(View view, T t, int type, int pos) {

        }
    };
//    设置点击事件
    public void SetOnClickListener(AdapterOnItemClick<T> adapterOnItemClick) {
        this.mAdapterOnItemClick = adapterOnItemClick;
    }

    ;

    //    获取点击事件
    public void setActivityItemClick(View view, T t, int type, int pos) {
        mAdapterOnItemClick.click(view, t, type, pos);
    }

    //    设置长点击事件
    public void SetOnLongClickListener(AdapterOnLongItemClick<T> adapterOnLongItemClick) {
        this.mAdapterOnLongItemClick = adapterOnLongItemClick;
    }

    ;

    //   获取长点击事件
    public void setActivityLongItemClick(View view, T t, int type, int pos) {
        mAdapterOnLongItemClick.click(view, t, type, pos);
    }

接下来为了实现数据的增删改我们添加了

//    增加
    public void upData(List<T> t) {
        this.mData = t;
        notifyDataSetChanged();
    }
    public void upData(T t) {
        mData.add(t);
        notifyDataSetChanged();
    }
//    修改
    public void setData(int pos,T t) {
        mData.set(pos,t);
        notifyDataSetChanged();
    }
    public void setData(T t) {
        int index = mData.indexOf(t);
        if (index>=0){
            mData.set(index,t);
            notifyDataSetChanged();
        }
    }
//    删除
    public void remove(T t) {
        int index = mData.indexOf(t);
        if (index >= 0) {
            mData.remove(t);
            notifyItemRemoved(index);
        }
    }

    public void remove(int index) {
        if (index >= 0) {
            mData.remove(index);
            notifyItemRemoved(index);
        }
    }
//删除全部
    public void removeAll() {
        this.mData.clear();
        notifyDataSetChanged();
    }

这样 简单的adpter就实现了

2.多布局BaseAdapter的实现

多布局就不得不说getItemViewType方法了 adpter会先调用这个方法在调用onCreateViewHolder方法
在将viewType返回过去所以我们加入了多布局的接口

/**
 * @author li
 * 版本:1.0
 * 创建日期:2020/6/12 15
 * 描述:实现多布局
 */
public interface MixtureLayout<T> {
    public int getLayoutId(T data,int postion);
}

    /*多布局情况下初始化*/
    public BaseAdapter(Context context, List<T> data, MixtureLayout<T> mixtureLayout) {
        this(context, data, -1);
        this.mMixtureLayout = mixtureLayout;
    }

  @Override
    public int getItemViewType(int position) {
        if (mMixtureLayout != null) {
//           多布局情况下返回 布局Id
            return mMixtureLayout.getLayoutId(mData.get(position), position);
        }
        return super.getItemViewType(position);
    }

在onCreateViewHolder方法中我们要新增

   private MixtureLayout<T> mMixtureLayout;
   @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (mMixtureLayout != null) {
            mLayoutId = viewType;
        }
        if (mLayoutId == -1)
            throw new Resources.NotFoundException("没有找到该mLayoutId");
        View view = mLayoutInflater.inflate(mLayoutId, parent, false);
//       创建ViewHolder
        mViewHolder = new ViewHolder(view);
        return mViewHolder;
    }

到此BaseAdpter功能基本实现完成

3.BaseAdapter的使用

/**
 * @author li
 * 版本:1.0
 * 创建日期:2020/6/11 20
 * 描述:
 */
public class SimpleAdapter extends BaseAdapter<String> {
    private Context mContext;
    public SimpleAdapter(Context context, List<String> data, int layoutId) {
        super(context, data, layoutId);
        this.mContext = context;
    }

    @Override
    protected void bindViewHolder(ViewHolder holder, final String strings, final int position) {
        //      链式调用
        holder.setText(R.id.tv_title1,strings)
                .setText(R.id.tv_title2,"哈哈哈");
        //       自定义网咯图片解析方式
        holder.setImageView(R.id.iv_pic,
                "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1591887961825&di=b46faa0b1254616dd4f1a36653f36fef&imgtype=0&src=http%3A%2F%2Fa3.att.hudong.com%2F14%2F75%2F01300000164186121366756803686.jpg"
                 , new MyImageLoader(mContext));
        //       adapter 内部的点击事件
        holder.setOnItemClick(R.id.iv_pic, new OnItemClick() {
            @Override
            public void click(View view) {
                Log.e("TAG", "click: ----------" );
                //               回调到activity中 根据type判断谁点击
                setActivityItemClick(view,strings,1,position);
            }
        });
        holder.setOnItemClick(R.id.tv_title1, new OnItemClick() {
            @Override
            public void click(View view) {
                Log.e("TAG", "click: ----------" );
                setActivityItemClick(view,strings,2,position);
            }
        });
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("TAG", "click: ----------" );
                setActivityItemClick(v,strings,3,position);
            }
        });
        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                setActivityLongItemClick(v,strings,1,position);
                return true;
            }
        });
    }



}

其中MyImageLoader 我是这么实现的

/**
 * @author li
 * 版本:1.0
 * 创建日期:2020/6/11 19
 * 描述:
 */
public class MyImageLoader implements ViewHolder.ImageLoader {
    private Context mContext;

    public MyImageLoader(Context context) {
        this.mContext = context;
    }

    @Override
    public void loadImage(ImageView imageView, String url) {
//      实现MyImageLoader 方法自定义网咯图片的解析方法更容易扩展
        Glide.with(mContext).load(url).into(imageView);
    }
}

简简单单几行搞定 复杂的使用

/**
 * @author li
 * 版本:1.0
 * 创建日期:2020/6/11 20
 * 描述:
 */
public class MixLayoutAdapter extends BaseAdapter<String> {
    private Context mContext;
    public MixLayoutAdapter(Context context, List<String> data) {
        super(context, data, new MixtureLayout<String>() {
            @Override
            public int getLayoutId(String data,int pos) {
                if ((pos+1)%2 ==0){
                    return R.layout.item_simple;
                }else {
                    return R.layout.item_simple2;
                }
            }
        });
        this.mContext = context;
    }

    @Override
    protected void bindViewHolder(ViewHolder holder, final String strings, final int position) {
//      链式调用
	//根据holder.getLayoutId()来区分不同的item 这里我使用的布局只是位置有区别
        Log.e("TAG", "onCreateViewHolder: -->"+ (holder.getLayoutId()==R.layout.item_simple)+ (holder.getLayoutId()==R.layout.item_simple2));
        holder.setText(R.id.tv_title1,strings)
                .setText(R.id.tv_title2,"哈哈哈");
//       自定义网咯图片解析方式
        holder.setImageView(R.id.iv_pic,
                "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1591887961825&di=b46faa0b1254616dd4f1a36653f36fef&imgtype=0&src=http%3A%2F%2Fa3.att.hudong.com%2F14%2F75%2F01300000164186121366756803686.jpg"
                 , new MyImageLoader(mContext));
//       adapter 内部的点击事件
        holder.setOnItemClick(R.id.iv_pic, new OnItemClick() {
            @Override
            public void click(View view) {
                Log.e("TAG", "click: ----------" );
//               回调到activity中 根据type判断谁点击
                setActivityItemClick(view,strings,1,position);
            }
        });
        holder.setOnItemClick(R.id.tv_title1, new OnItemClick() {
            @Override
            public void click(View view) {
                Log.e("TAG", "click: ----------" );
                setActivityItemClick(view,strings,2,position);
            }
        });
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("TAG", "click: ----------" );
                setActivityItemClick(v,strings,3,position);
            }
        });
        holder.setOnLongItemClick(R.id.iv_pic, new OnLongItemClick() {
            @Override
            public void click(View view) {
                Log.e("TAG", "Longclick: ----------" );
                setActivityLongItemClick(view,strings,1,position);
            }
        });
    }

源码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值