您的位置:首页 > 其它

Recycleview之打造通用的Adapter

2020-06-26 04:28 92 查看

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);
}
});
}

源码

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: