这个封装适用于一个数据结构/通过数据参数的不同展示不同想过的情况.
适配器
次适配器使用是不需要对该适配器进行操作修改
/**
* 使用时 无需都是此 Adapter 进行修改
*/
public class BaseAdapterRecycler extends RecyclerView.Adapter {
protected Context mContext;
//.数据源
protected List mDatas;
//.点击监听
private OnItemClickListener mOnItemClickListener;
//.模版管理 SparseArrayCompat 使用方法见末尾
private SparseArrayCompat> mTemplates;
/**
* 构造方法
*
* @param context
*/
public BaseAdapterRecycler(Context context) {
this.mContext = context;
mTemplates = new SparseArrayCompat<>();
}
/**
* 构造方法
*
* @param context
* @param datas
*/
public BaseAdapterRecycler(Context context, List datas) {
this(context);
this.setmDatas(datas);
}
/**
* 设置数据源
*
* @param datas
*/
public void setmDatas(List datas) {
this.mDatas = datas;
notifyDataSetChanged();
}
/**
* 获取布局类型
*
* @param position
* @return
*/
@Override
public int getItemViewType(int position) {
//如果数组越界 执行默认操作
if (isOutOfBounds(position)) {
return super.getItemViewType(position);
} else {
//循环遍历 布局类型
for (int i = mTemplates.size() - 1; i >= 0; i--) {
ItemTemplate itemTemplate = mTemplates.valueAt(i);
if (itemTemplate.isForViewType(mDatas.get(position))) {
//如果是当前模版样式 , 返回当前位置的键 便于 onCreateViewHolder()时获取 模版
//当前位置的键 与当前位置 存在不相同的情况,当调用了 addItemTemplate()双参数 的方法时可能会不同
return mTemplates.keyAt(i);
}
}
return super.getItemViewType(position);
}
}
/**
* 生成 ViewHolder
*
* @param viewGroup
* @param viewType
* @return
*/
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
//获取模版样式
ItemTemplate itemTemplate = mTemplates.get(viewType);
//生成 ViewHolder
ViewHolder holder = ViewHolder.createViewHolder(mContext, viewGroup, itemTemplate.getLayoutID());
//设置监听
setListener(viewGroup, holder, viewType);
return holder;
}
/**
* 数据绑定 ViewHolder
*
* @param viewHolder
* @param position
*/
@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
DATA data = mDatas.get(position);
for (int i = 0; i < mTemplates.size(); i++) {
ItemTemplate template = mTemplates.valueAt(i);
if (template.isForViewType(data)) {
template.convert(viewHolder, data, position);
}
}
}
/**
* 动态设置 布局样式为 GridLayoutManager时,每类布局列数
* recyclerView设置GridLayoutManager 时,SpanCount 设置为几类布局列数的最小公倍数
* 例如:
* 布局A:2列
* 布局B:3列
* 布局C:2列
* 布局D:1列
* 则SpanCount 设置为 6
* 对应的Bean类中设置为
* A:3(6/2)
* B:2(6/3)
* C:3(6/2)
* D:6(6/1)
*
* 其实此处就是把 RecyclerView当成了一个表格,
* 设置的是每一个 Item 所占的列数
*
* @param recyclerView
*/
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager lm = recyclerView.getLayoutManager();
if (lm instanceof GridLayoutManager) {
((GridLayoutManager) lm).setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
DATA data = mDatas.get(position);
for (int i = 0; i < mTemplates.size(); i++) {
ItemTemplate template = mTemplates.valueAt(i);
if (template.isForViewType(data)) {
return template.getSpanCount();
}
}
return 1;
}
});
}
}
/**
* 获取 数据源数量
*
* @return
*/
@Override
public int getItemCount() {
return mDatas == null ? 0 : mDatas.size();
}
/**
* 获取数据源
*
* @return
*/
public List getDatas() {
return mDatas;
}
/**
* 添加数据源
*
* @param data
* @return
*/
public BaseAdapterRecycler addData(DATA data) {
if (mDatas == null) {
mDatas = new ArrayList<>();
}
if (data != null) {
mDatas.add(data);
} else {
log("data is null");
}
notifyDataSetChanged();
return this;
}
/**
* 添加多条数据源
*
* @param datas
* @return
*/
public BaseAdapterRecycler addData(List datas) {
if (mDatas == null) {
mDatas = new ArrayList<>();
}
if (datas != null) {
mDatas.addAll(datas);
} else {
log("data is null");
}
notifyDataSetChanged();
return this;
}
/**
* 在指定位置添加数据源
*
* @param position
* @param data
* @return
*/
public BaseAdapterRecycler addData(@IntRange(from = 0) int position, DATA data) {
if (mDatas == null) {
mDatas = new ArrayList<>();
}
if (isOutOfBounds(position)) {
log("addData() position 越界 ,默认添加到最后");
position = getItemCount();
}
if (data != null) {
mDatas.add(position, data);
} else {
log("data is null");
}
notifyDataSetChanged();
return this;
}
/**
* 在指定位置添加多条数据源
*
* @param position
* @param datas
* @return
*/
public BaseAdapterRecycler addData(@IntRange(from = 0) int position, List datas) {
if (mDatas == null) {
mDatas = new ArrayList<>();
}
if (isOutOfBounds(position)) {
log("addData() position 越界 ,默认添加到最后");
position = getItemCount();
}
if (datas != null) {
mDatas.addAll(position, datas);
} else {
log("datas is null");
}
notifyDataSetChanged();
return this;
}
/**
* 移除 position 位置的数据
*
* @param position
* @return
*/
public BaseAdapterRecycler deleteData(@IntRange(from = 0) int position) {
return removeData(position);
}
/**
* 移除 position 位置的数据
*
* @param position
* @return
*/
public BaseAdapterRecycler removeData(@IntRange(from = 0) int position) {
if (mDatas == null) {
mDatas = new ArrayList<>();
}
if (isOutOfBounds(position)) {
log("removeData() position 越界");
} else {
mDatas.remove(position);
}
notifyDataSetChanged();
return this;
}
/**
* 设置监听
* 此方法设置监听适用于统一处理的情况
* 不同模版监听处理不同的情况 建议在各自模版中进行设置(holder.itemView.setOnclickListener(this))
*
* @param viewGroup
* @param holder
* @param viewType
*/
private void setListener(ViewGroup viewGroup, ViewHolder holder, int viewType) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(v, holder, holder.getAdapterPosition());
}
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemLongClick(v, holder, holder.getAdapterPosition());
}
return false;
}
});
}
/**
* 设置监听
*
* @param onItemClickListener
*/
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.mOnItemClickListener = onItemClickListener;
}
/**
* 判断 position 是否越界
*
* @param position
* @return
*/
private boolean isOutOfBounds(int position) {
if (mDatas == null || mDatas.isEmpty()) {
return true;
} else if (position < 0 || position >= mDatas.size()) {
return true;
} else {
return false;
}
}
/**
* 添加 样式模版
*
* @param itemTemplate
* @return
*/
public BaseAdapterRecycler addItemTemplate(ItemTemplate itemTemplate) {
if (itemTemplate != null) {
mTemplates.put(mTemplates.size(), itemTemplate);
} else {
log("itemTemplate is null");
}
return this;
}
/**
* 添加 样式模版
*
* @param viewType
* @param itemTemplate
* @return
*/
public BaseAdapterRecycler addItemTemplate(int viewType, ItemTemplate itemTemplate) {
if (mTemplates.get(viewType) != null) {
log("模版样式" + viewType + "已经存在," + "存在的模版样式为" + mTemplates.get(viewType));
}
if (itemTemplate != null) {
log("已将原模版" + mTemplates.get(viewType) + "替换");
mTemplates.put(viewType, itemTemplate);
}
return this;
}
/**
* 监听接口
*/
public interface OnItemClickListener {
void onItemClick(View view, RecyclerView.ViewHolder holder, int position);
boolean onItemLongClick(View view, RecyclerView.ViewHolder holder, int position);
}
/**
* 打印信息
*
* @param log
*/
private void log(String log) {
Log.e(getClass().getName(), log);
}
/**
* SparseArray(API >19 ) SparseArrayCompat(兼容)
* android 独有的类
* 类似于 HashMap 但是性能更优化
*/
/*
增
put(int key, E value)
append(int key, E value)
查
public E get(int key)
public E get(int key, E valueIfKeyNotFound)
//查不到时的默认值
//查看第 index 个位置的键
public int keyAt(int index)
//查看第 index 个位置的值
public E valueAt(int index)
//查看键所在位置 键不存在 返回 <0(不一定是-1)
public int indexOfKey(int key)
//查看值所在位置 值不存在 返回 -1
public int indexOfValue(E value)
删
public void delete(int key)
public void remove(int key)
public void removeAt(int index)
public void clear()
改
public void setValueAt(int index, E value)
public void put(int key, E value)
*/
}
复用器 ViewHolder
使用时 此类也无需修改.
如果项目中添加了插件或者jar包(Glide …),可以适当修改
/**
* 使用时此类可以不进行修改
*/
public class ViewHolder extends RecyclerView.ViewHolder {
private Context mContext;
private View mConvertView;
private SparseArray mViews;
public ViewHolder(Context context, @NonNull View itemView) {
super(itemView);
mContext = context;
mConvertView = itemView;
mViews = new SparseArray();
}
/**
* 创建 ViewHolder 实例
*
* @param context
* @param itemView
* @return
*/
public static ViewHolder createViewHolder(Context context, View itemView) {
return new ViewHolder(context, itemView);
}
/**
* 创建 ViewHolder 实例
*
* @param context
* @param parent
* @param layoutRes
* @return
*/
public static ViewHolder createViewHolder(Context context, ViewGroup parent, @LayoutRes int layoutRes) {
return new ViewHolder(context, LayoutInflater.from(context).inflate(layoutRes, null));
}
/**
* 获取 弱引用 对象控件
*
* @param idRes
* @return
*/
public WeakReference getWeakReference(@IdRes int idRes) {
if (mViews.get(idRes) == null) {
mViews.put(idRes, itemView.findViewById(idRes));
}
return new WeakReference<>(mViews.get(idRes));
}
/**
* 根据 控件 idRes 获取 控件
*
* @param idRes
* @param
* @return
*/
public V getView(@IdRes int idRes) {
if (mViews.get(idRes) == null) {
mViews.put(idRes, itemView.findViewById(idRes));
}
if (mViews.get(idRes) == null) {
throw new NullPointerException(idRes + "不存在");
}
return (V) mViews.get(idRes);
}
///********************以下为辅助方法 使用方法一致*****************************************///
/**
* 设置 TextView 控件的值
*
* @param idRes
* @param sequence
* @return
*/
public ViewHolder setText(@IdRes int idRes, CharSequence sequence) {
TextView tv = getView(idRes);
if (tv == null) {
return this;
}
if (sequence == null || sequence.length() == 0) {
tv.setVisibility(View.INVISIBLE);
} else {
tv.setText(sequence);
}
return this;
}
/**
* 设置 TextView 字体颜色
*
* @param idRes
* @param color
* @return
*/
public ViewHolder setTextColor(@IdRes int idRes, @ColorInt int color) {
TextView tv = getView(idRes);
tv.setTextColor(color);
return this;
}
/**
* 设置 TextView 控件的值及字体颜色
*
* @param idRes
* @param sequence
* @param color
* @return
*/
public ViewHolder setText(@IdRes int idRes, CharSequence sequence, @ColorInt int color) {
TextView tv = getView(idRes);
tv.setTextColor(color);
setText(idRes, sequence);
return this;
}
/**
* 通过 Resources 资源 设置 TextView 的值
*
* @param idRes
* @param stringRes
* @return
*/
public ViewHolder setText(@IdRes int idRes, @StringRes int stringRes) {
return setText(idRes, mContext.getResources().getString(stringRes));
}
/**
* 设置 TextView 的值及颜色
*
* @param idRes
* @param stringRes
* @param color
* @return
*/
public ViewHolder setText(@IdRes int idRes, @StringRes int stringRes, @ColorInt int color) {
return setText(idRes, mContext.getResources().getString(stringRes), color);
}
public @interface LinkifyMask {
}
/**
* 设置 TextView 的超链接
*
* @param idRes
* @param linkify
* @return
*/
public ViewHolder setTextLinkify(@IdRes int idRes, @LinkifyMask int linkify) {
// Linkify.WEB_URLS 网址
// Linkify.EMAIL_ADDRESSES 邮箱地址
// Linkify.PHONE_NUMBERS 电话号码
// Linkify.MAP_ADDRESSES map地址
// Linkify.ALL 全部
TextView tv = getView(idRes);
Linkify.addLinks(tv, linkify);
return this;
}
/**
* 设置 ImageView 的 滤镜颜色
*
* @param idRes
* @param colorRes
* @return
*/
public ViewHolder setImageColor(@IdRes int idRes, @ColorRes int colorRes) {
return setImageColor(idRes, colorRes, PorterDuff.Mode.MULTIPLY);
}
/**
* 设置 ImageView 控件 滤镜颜色 及 样式
*
* @param idRes
* @param colorRes
* @param mode
* @return
*/
public ViewHolder setImageColor(@IdRes int idRes, @ColorRes int colorRes, PorterDuff.Mode mode) {
ImageView iv = getView(idRes);
iv.setColorFilter(colorRes, mode);
// PorterDuff.Mode.CLEAR;//在源图像覆盖的目标图像的像素被清除为0
// PorterDuff.Mode.SRC;//源图
// PorterDuff.Mode.DST;//只绘制目标图像
// PorterDuff.Mode.SRC_OVER;//将源图像放到目标图像的上方
// PorterDuff.Mode.DST_OVER;//在源图像的上方绘制目标图像
// PorterDuff.Mode.SRC_IN;//绘制源图像和目标图像相交的部分的源图像,舍弃原图像和目标图像其他的部分
// PorterDuff.Mode.DST_IN;//绘制源图像和目标图像相交的部分的目标图像,舍弃原图像和目标图像其他的部分
// PorterDuff.Mode.SRC_OUT;//只绘制目标图像未覆盖的源图像的部分
// PorterDuff. Mode.DST_OUT;//只绘制目标图像与源图像不相交的部分
// PorterDuff.Mode.SRC_ATOP;//在源图像和目标图像相交的地方绘制源图像,在不相交的地方绘制目标图像
// PorterDuff.Mode.DST_ATOP;//在源图像和目标图像相交的地方绘制目标图像,而在不相交的地方绘制源图像
// PorterDuff.Mode.XOR;//源图像和目标图像相交的部分的像素清除为0,然后绘制剩余的源图像
// PorterDuff.Mode.ADD;
// PorterDuff.Mode.MULTIPLY;//只绘制源图像和目标图像相交的部分,而混合后图像像素的颜色值为源图像素颜色值乘以目标图像素颜色值除以255即得
// PorterDuff.Mode.SCREEN;//滤色:在源图像和目标图像相交的部分添加源图像和目标图像像素,然后减去目标图像与源像素相乘的。
// PorterDuff.Mode.OVERLAY;//根据目标图像的颜色,对源图片和目标图片的像素地进行倍增或屏蔽。
// PorterDuff.Mode.DARKEN;//保留原图像和目标图像的像素的最小的分量,效果就是源图像和目标图像相交的部分变暗
// PorterDuff.Mode.LIGHTEN;//保留原图像和目标图像的像素的最大的分量,效果就是源图像和目标图像相交的部分变亮
return this;
}
/**
* 清楚 ImageView 控件的滤镜颜色
*
* @param idRes
* @return
*/
public ViewHolder clearImageColor(@IdRes int idRes) {
ImageView iv = getView(idRes);
iv.clearColorFilter();
return this;
}
/**
* 设置 ImageView 控件
*
* @param idRes
* @param resId
* @return
*/
public ViewHolder setImageResources(@IdRes int idRes, @DrawableRes int resId) {
ImageView iv = getView(idRes);
iv.setImageResource(resId);
return this;
}
/**
* 设置控件背景色
*
* @param idRes
* @param color
* @return
*/
public ViewHolder setBackgroundColor(@IdRes int idRes, @ColorInt int color) {
getView(idRes).setBackgroundColor(color);
return this;
}
/**
* 设置控件背景色
*
* @param idRes
* @param resId
* @return
*/
public ViewHolder setBackgroundColorRes(@IdRes int idRes, @ColorRes int resId) {
setBackgroundColor(idRes, mContext.getResources().getColor(resId));
return this;
}
/**
* 设置控件背景
*
* @param idRes
* @param resId
* @return
*/
public ViewHolder setBackgroundRes(@IdRes int idRes, @DrawableRes int resId) {
getView(idRes).setBackgroundResource(resId);
return this;
}
/**
* 设置控件 隐藏
*
* @param idRes
* @return
*/
public ViewHolder setGone(@IdRes int idRes) {
getView(idRes).setVisibility(View.GONE);
return this;
}
/**
* 设置控件 显示
*
* @param idRes
* @return
*/
public ViewHolder setVisible(@IdRes int idRes) {
getView(idRes).setVisibility(View.VISIBLE);
return this;
}
/**
* 设置控件 占位隐藏
*
* @param idRes
* @return
*/
public ViewHolder setInVisible(@IdRes int idRes) {
getView(idRes).setVisibility(View.INVISIBLE);
return this;
}
/**
* 设置 ProgressBar 初始值
*
* @param idRes
* @param progress
* @return
*/
public ViewHolder setProgress(@IdRes int idRes, int progress) {
ProgressBar bar = getView(idRes);
bar.setProgress(progress);
return this;
}
/**
* 设置 ProgressBar 初始值和最大值
*
* @param idRes
* @param progress
* @param max
* @return
*/
public ViewHolder setProgress(@IdRes int idRes, int progress, int max) {
ProgressBar bar = getView(idRes);
bar.setProgress(progress);
bar.setMax(max);
return this;
}
/**
* 设置 ProgressBar 最大值
*
* @param idRes
* @param max
* @return
*/
public ViewHolder setProgressMax(@IdRes int idRes, int max) {
ProgressBar bar = getView(idRes);
bar.setMax(max);
return this;
}
/**
* 设置控件的 Tag
*
* @param idRes
* @param tag
* @return
*/
public ViewHolder setTag(@IdRes int idRes, Object tag) {
getView(idRes).setTag(tag);
return this;
}
/**
* 设置 控件多个 Tag
*
* @param idRes
* @param key
* @param tag
* @return
*/
public ViewHolder setTag(@IdRes int idRes, @StringRes int key, Object tag) {
getView(idRes).setTag(key, tag);
return this;
}
/**
* 设置 控件选中/不选中
*
* @param idRes
* @param checked
* @return
*/
public ViewHolder setChecked(@IdRes int idRes, boolean checked) {
Checkable checkable = getView(idRes);
checkable.setChecked(checked);
return this;
}
/**
* 设置控件点击监听
*
* @param idRes
* @param listener
* @return
*/
public ViewHolder setOnClickListener(@IdRes int idRes, View.OnClickListener listener) {
getView(idRes).setOnClickListener(listener);
return this;
}
/**
* 设置控件触摸监听
*
* @param idRes
* @param listener
* @return
*/
public ViewHolder setOnTouchListener(@IdRes int idRes, View.OnTouchListener listener) {
getView(idRes).setOnTouchListener(listener);
return this;
}
/**
* 设置控件长按监听
*
* @param idRes
* @param listener
* @return
*/
public ViewHolder setOnLongClickListener(@IdRes int idRes, View.OnLongClickListener listener) {
getView(idRes).setOnLongClickListener(listener);
return this;
}
/**
* 设置控件选中监听
*
* @param idRes
* @param listener
* @return
*/
public ViewHolder setOnListener(@IdRes int idRes, CompoundButton.OnCheckedChangeListener listener) {
CheckBox cb = getView(idRes);
cb.setOnCheckedChangeListener(listener);
return this;
}
/**
* 获取控件的 Tag
*
* @param idRes
* @return
*/
public Tag getTag(@IdRes int idRes) {
return (Tag) getView(idRes).getTag();
}
/**
* 获取控件的 多个Tag
*
* @param idRes
* @param key
* @return
*/
public Tag getTag(@IdRes int idRes, @StringRes int key) {
return (Tag) getView(idRes).getTag(key);
}
}
布局模版接口
public interface ItemTemplate {
/**
* 获取模版布局
*
* @return
*/
int getLayoutID();
/**
* 判断当前 item 的模版是否为本模版
*
* @param data
* @return
*/
boolean isForViewType(DATA data);
/**
* 使用 GridLayoutManager 时,不同的列数所占据的比重
* 设置为几类布局列数的最小公倍数
* 例如:
* 布局A:2列
* 布局B:3列
* 布局C:2列
* 布局D:1列
* 则SpanCount 设置为 6
* 对应的Bean类中设置为
* A:3(6/2)
* B:2(6/3)
* C:3(6/2)
* D:6(6/1)
*
* 其实此处就是把 RecyclerView当成了一个表格,
* 设置的是每一个 Item 所占的列数
* JAVA 8 方法
* @return
*/
default int getSpanCount(){
return 1;
}
/**
* 模版数据绑定
* @param holder
* @param data
* @param position
*/
void convert(ViewHolder holder, DATA data, int position);
}
特别注意getSpanCount()
此方法在RecyclerView 设置 布局为 GridLayoutManager 时才会调用,对于所有的布局模版列数均相同时可以实现此方法,其他情况均需复写此方法.
public class Template implements ItemTemplate {
/**
* 模版布局
*
* @return
*/
@Override
public int getLayoutID() {
return R.layout.layout_1;
}
/**
* 判断是否为该模版
*
* @param baseBean
* @return
*/
@Override
public boolean isForViewType(String baseBean) {
return true;
}
/**
* 数据绑定
*
* @param holder
* @param baseBean
* @param position
*/
@Override
public void convert(ViewHolder holder, String baseBean, int position) {
holder.setText(R.id.tv, baseBean);
}
}
xml 就不发了,都是最简单的