偷懒新姿势,打造属于RecyclerView的万能适配器Adapter和ViewHolder
时间:2022-04-26
本文章向大家介绍偷懒新姿势,打造属于RecyclerView的万能适配器Adapter和ViewHolder,主要内容包括前言、正统模式:、封装后的Adapter、Super ViewHolder、实践用法、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。
前言
昨天开始接触江湖口碑很好的RecyclerView,事实上,我已经被她的强大所征服了!资源回收,数据绑定,布局显示,分割线,Item动画多个模块高度解耦,灵活优雅。其实,RecyclerView在使用上已经是相当简单了(个人觉得),但仍有很多代码是可以加以封装的。今天受简书上一篇博文的启发,作为写代码喜欢优(tou)雅(lan)的人,想到了一种封装方式,打造万能适配器,供大家食用。
正统模式:
public class SimplerItemAdapter extends RecyclerView.Adapter<SimplerItemAdapter.SimpleItemViewHolder > {
private List <String> items;
public SimplerItemAdapter (@NonNull List<String> dateItems ) { this.items = (dateItems != null ? dateItems : new ArrayList<String>());
}
@Override
public SimpleItemViewHolder onCreateViewHolder (ViewGroup viewGroup, int viewType) {
View itemView = LayoutInflater.from( viewGroup.getContext ()).inflate(R.layout .item, viewGroup, false );
return new SimpleItemViewHolder(itemView);
}
@Override
public void onBindViewHolder (SimpleItemViewHolder viewHolder, int position) {
viewHolder.textView .setText(items.get (position));
}
@Override
public int getItemCount () {
return (this.items != null) ? this .items. size() : 0 ;
}
protected final static class SimpleItemViewHolder extends RecyclerView.ViewHolder {
protected TextView textView ;
public SimpleItemViewHolder (View itemView) {
super(itemView);
this.textView = (TextView) itemView.findViewById (R. id.text); }
}
}
- 首先,
@Override public int getItemCount () {
return (this.items != null) ? this .items. size() : 0 ;
}
这段代码完全可以封装起来的。 - onCreatedViewHolder()方法作用是绑定item视图,可以进一步封装,给子类提供一个getLayoutItemId的抽象方法,这样就可以简化成一行代码了。
- 因此我们发现,这个adapter的核心代码在与onBindViewHolder()中,作用是将数据跟视图(ViewHolder)绑定,可以给子类提供一个bindData()抽象方法。
- 当然了,使用泛型也是极好的,拓广了adapter的使用范围。
- 添加点击事件的监听也可以封装到万能adapter中,子类就不用再写item点击事件处理代码了
封装后的Adapter
public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter<RecyclerViewHolder> {
protected final List<T> mData;
protected final Context mContext;
protected LayoutInflater mInflater;
private OnItemClickListener mClickListener;
private OnItemLongClickListener mLongClickListener;
public BaseRecyclerAdapter(Context ctx, List<T> list) { mData = (list != null) ? list : new ArrayList<T>(); mContext = ctx;
mInflater = LayoutInflater.from(ctx);
}
@Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final RecyclerViewHolder holder = new RecyclerViewHolder(mContext,
mInflater.inflate(getItemLayoutId(viewType), parent, false)); if (mClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v) {
mClickListener.onItemClick(holder.itemView, holder.getLayoutPosition());
} });
}
if (mLongClickListener != null) {
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
mLongClickListener.onItemLongClick(holder.itemView, holder.getLayoutPosition());
return true;
} });
}
return holder;
}
@Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
bindData(holder, position, mData.get(position));
}
@Override
public int getItemCount() {
return mData.size();
}
public void add(int pos, T item) {
mData.add(pos, item);
notifyItemInserted(pos);
}
public void delete(int pos) {
mData.remove(pos);
notifyItemRemoved(pos);
}
public void setOnItemClickListener(OnItemClickListener listener) {
mClickListener = listener;
}
public void setOnItemLongClickListener(OnItemLongClickListener listener) {
mLongClickListener = listener;
}
abstract public int getItemLayoutId(int viewType);
abstract public void bindData(RecyclerViewHolder holder, int position, T item);
public interface OnItemClickListener {
public void onItemClick(View itemView, int pos);
}
public interface OnItemLongClickListener {
public void onItemLongClick(View itemView, int pos);
}
}
Super ViewHolder
其实,这还没完呢!重头戏在ViewHolder上!RecyclerView强制我们使用ViewHolder模式,然而缺不可避免地要写findViewById代码,有没有办法不写这样的代码呢?甚至连ViewHolder都不写呢?当然可以!
public class RecyclerViewHolder extends RecyclerView.ViewHolder { private SparseArray<View> mViews;
private Context mContext;
public RecyclerViewHolder(Context ctx, View itemView) { super(itemView);
mContext = ctx;
mViews = new SparseArray<View>();
}
private <T extends View> T findViewById(int viewId) { View view = mViews.get(viewId);
if (view == null) {
view = itemView.findViewById(viewId);
mViews.put(viewId, view);
}
return (T) view;
}
public View getView(int viewId) {
return findViewById(viewId);
}
public TextView getTextView(int viewId) {
return (TextView) getView(viewId);
}
public Button getButton(int viewId) {
return (Button) getView(viewId);
}
public ImageView getImageView(int viewId) {
return (ImageView) getView(viewId);
}
public ImageButton getImageButton(int viewId) {
return (ImageButton) getView(viewId);
}
public EditText getEditText(int viewId) {
return (EditText) getView(viewId);
}
public RecyclerViewHolder setText(int viewId, String value) { TextView view = findViewById(viewId);
view.setText(value);
return this;
}
public RecyclerViewHolder setBackground(int viewId, int resId) {
View view = findViewById(viewId);
view.setBackgroundResource(resId);
return this;
}
public RecyclerViewHolder setClickListener(int viewId, View.OnClickListener listener) {
View view = findViewById(viewId);
view.setOnClickListener(listener);
return this; }
}
该类的核心方法是private T findViewById(int viewId),核心成员变量是private SparseArray mViews; 不信可以不写一句ViewHolder代码?接下来看看用法。
实践用法
添加Adapter仅需短短的几行代码:
Adapter = new BaseRecyclerAdapter<String>(this,mDataList) { @Override
public int getItemLayoutId(int viewType) {
return R.layout.item;
}
@Override
public void bindData(RecyclerViewHolder holder, int position,String item) {
//调用holder.getView(),getXXX()方法根据id得到控件实例,进行数据绑定即可
holder.setText(R.id.tv_num,item).getTextView(R.id.tv_title,item).setText(item);
}
};
完整代码:
private void init() {
recyclerView = (RecyclerView) findViewById(R.id.recyclerView); mDataList = new ArrayList<>();
for (int i = 0; i <= 100; i++) {
mDataList.add(String.valueOf(i));
}
//设置item动画
recyclerView.setItemAnimator(new DefaultItemAnimator()); mAdapter = new BaseRecyclerAdapter<String>(this,mDataList) {
@Override
public int getItemLayoutId(int viewType) {
return R.layout.item;
}
@Override
public void bindData(RecyclerViewHolder holder, int position,String item) {
//调用holder.getView(),getXXX()方法根据id得到控件实例,进行数据绑定即可
holder.setText(R.id.tv_num,item).getTextView(R.id.tv_title,item).setText(item);
}
};
recyclerView.setAdapter(mAdapter);
//添加item点击事件监听
((BaseRecyclerAdapter)mAdapter).setOnItemClickListener(new BaseRecyclerAdapter.OnItemClickListener() {
@Override
public void onItemClick(View itemView, int pos) { Toast.makeText(AdapterTestActivity.this, "click " + pos, Toast.LENGTH_SHORT).show();
}
});
((BaseRecyclerAdapter)mAdapter).setOnItemLongClickListener(new BaseRecyclerAdapter.OnItemLongClickListener() {
@Override
public void onItemLongClick(View itemView, int pos) { Toast.makeText(AdapterTestActivity.this, "long click " + pos, Toast.LENGTH_SHORT).show();
}
});
//设置布局样式LayoutManager
recyclerView.setLayoutManager(new LinearLayoutManager(AdapterTestActivity.this, LinearLayoutManager.VERTICAL, false));
// recyclerView.addItemDecoration(new ItemDividerDecoration(MainActivity.this, OrientationHelper.VERTICAL));
}
如果觉得有什么不妥之处或建议,敬请指教! 完整项目代码已上传至Github(https://github.com/TellH/RecyclerViewDemo)。
- Oracle 12C打补丁的简单尝试(r10笔记第55天)
- 【Go 语言社区】奇妙的go语言(网页下载)-转
- 【Go 语言社区】golang的bufio用于内容解析
- [Go语言]从Docker源码学习Go——指针和Structs - lemon_bar
- Git 项目推荐 | Go 语言读写 INI 文件工具包
- 初识Python (r10笔记第52天)
- 挑战数据结构与算法面试题——统计上排数在下排出现的次数
- Go语言的 10 个实用技术--转
- MySQL反连接的优化总结(r10笔记第51天)
- python基础知识——内置数据结构(列表)
- 【Go 语言社区】Go语言Slice去重
- 【Go 语言社区】Golang 语言再谈接口
- 【Go 语言社区】Golang 语言再谈常量
- 【Go 语言社区】HTML5 Canvas+JS控制电脑或手机上的摄像头实例
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Tensorflow小技巧整理:
- Tensorflow学习笔记——Summary用法
- 神经网络优化(损失函数:自定义损失函数、交叉熵、softmax())
- C++ STL stack 用法
- 遍历string时 使用for(char& c : s) for(char c : s) 的区别
- vc dll静态函数导出
- 利用GDB调试 MSQL
- 手把手教学-MySQL主从复制架构转换MGR架构(mysq_shell版)
- 手把手教学-MySQL主从复制架构转换MGR架构(手动版)
- 云数据库VS自建数据库,到底该如何抉择?
- 组复制常规操作-事务一致性保证 | 全方位认识 MySQL 8.0 Group Replication
- 面试题-算法:二叉树的前序遍历
- 黑客帝国中的代码雨
- 模型效果评价—混淆矩阵
- 用Python中的py2neo库调用neo4j,搭建简单关联图谱