本篇是对上一篇对RecyclerView.Adapter做一个简单的封装内容的补充 ,如果没有看过上一篇文章,请先阅读上一篇文章。
在上一篇文章的末尾提到,BaseRecyclerAdapter虽然能够简化部分功能的代码量,但是对于为itemView的每一个控件绑定监听器这一功能是没有做到简化的,本篇的内容就是解决这个问题。
先贴出没有封装的适配器代码
public class RecordAdapter extends RecyclerView.Adapter<RecordAdapter.RecordHolder> {
private OnItemClickListener onItemClickListener;
//上下文环境
private Context context;
//数据集合
private List<Record> data;
public RecordAdapter(Context context, List<Record> data) {
this.context = context;
this.data = data;
}
/**
* 刷新数据
* @param data
*/
public void refresh(List<Record> data){
this.data = data;
notifyDataSetChanged();
}
@Override
public RecordHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item_record, parent, false);
return new RecordHolder(view);
}
@Override
public void onBindViewHolder(RecordHolder holder, int position) {
Record record = data.get(position);
holder.bind(record);
}
@Override
public int getItemCount() {
return data == null ? 0 : data.size();
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
class RecordHolder extends RecyclerView.ViewHolder {
//数据
private Record record;
TextView tvId;
TextView tvRemark;
TextView tvCreatedAt;
public RecordHolder(View itemView) {
super(itemView);
tvId = (TextView) itemView.findViewById(R.id.tvId);
tvRemark = (TextView) itemView.findViewById(R.id.tvRemark);
tvCreatedAt = (TextView) itemView.findViewById(R.id.tvCreatedAt);
bindListener();
}
//绑定数据
public void bind(Record record) {
this.record = record;
tvId.setText(record.getId().toString());
tvRemark.setText(record.getRemark());
tvCreatedAt.setText(record.getCreatedAt().toString());
}
/**
* 绑定监听器
*/
private void bindListener() {
tvId.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onItemClickListener != null) {
onItemClickListener.onIdClick(v, record);
}
}
});
tvRemark.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onItemClickListener != null) {
onItemClickListener.onRemarkClick(v, record);
}
}
});
tvCreatedAt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onItemClickListener != null) {
onItemClickListener.onCreationTimeClick(v, record);
}
}
});
}
}
public interface OnItemClickListener {
/**
* 当id被点击
* @param v
* @param record
*/
void onIdClick(View v, Record record);
/**
* 当备注被点击
* @param v
* @param record
*/
void onRemarkClick(View v, Record record);
/**
* 当创建时间被点击
* @param v
* @param record
*/
void onCreationTimeClick(View v, Record record);
}
}
运行
MainActivity.java
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private RecordAdapter adapter;
private List<Record> records;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
//模拟数据
records = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Record record = new Record();
record.setId(i);
record.setRemark("第" + i + "条备注");
record.setCreatedAt(new Date());
records.add(record);
}
adapter = new RecordAdapter(this, records);
//绑定监听器
adapter.setOnItemClickListener(new RecordAdapter.OnItemClickListener() {
@Override
public void onIdClick(View v, Record record) {
Toast.makeText(MainActivity.this, record.getId().toString(), Toast.LENGTH_SHORT).show();
}
@Override
public void onRemarkClick(View v, Record record) {
Toast.makeText(MainActivity.this, record.getRemark(), Toast.LENGTH_SHORT).show();
}
@Override
public void onCreationTimeClick(View v, Record record) {
Toast.makeText(MainActivity.this, record.getCreatedAt().toString(), Toast.LENGTH_SHORT).show();
}
});
recyclerView.setAdapter(adapter);
}
}
运行效果如下
每个控件的点击效果可以自己亲自测试,接下来同样通过对比的方式讲解封装思路。
RecordAdapter中的回调接口OnItemClickListener
public interface OnItemClickListener {
/**
* 当id被点击
* @param v
* @param record
*/
void onIdClick(View v, Record record);
/**
* 当备注被点击
* @param v
* @param record
*/
void onRemarkClick(View v, Record record);
/**
* 当创建时间被点击
* @param v
* @param record
*/
void onCreationTimeClick(View v, Record record);
}
RecordHolder中的控件
TextView tvId;
TextView tvRemark;
TextView tvCreatedAt;
可以看到OnItemClickListener中的抽象方法是和RecordHolder中的控件是一一对应的,而在封装的BaseViewHolder中控件是这样的
// itemView 中的控件缓存在这里
private SparseArray<View> views;
那么BaseRecyclerAdapter中的回调接口应该怎么写?
不知道大家用没用过PopupMenu,PopupMenu绑定点击事件如下
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.view1:
...
break;
case R.id.view2:
...
break;
case R.id.view3:
...
break;
}
return false;
}
});
从这里可以获得灵感,为BaseViewHolder中所有的控件都绑定监听器,然后根据控件id的不同来做不同的操作。
BaseRecyclerAdapter中的OnItemClickListener
/**
* 回调接口
* @param <T>
*/
public interface OnItemClickListener<T> {
void onItemClick(View view, T t);
}
BaseViewHolder
class BaseViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
// itemView 中的控件缓存在这里
private SparseArray<View> views;
//数据
private T t;
public BaseViewHolder(View itemView) {
super(itemView);
views = new SparseArray<>();
}
public void setT(T t) {
this.t = t;
}
/**
* 获取 itemView 中的控件
*
* @param id
* @return
*/
public View getView(int id) {
View view = views.get(id);
if (view == null) {
view = itemView.findViewById(id);
views.put(id, view);
view.setOnClickListener(this);
}
return view;
}
@Override
public void onClick(View v) {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(v, t);
}
}
}
与之前的BaseViewHolder相比多了几处东西:
1.private T t
这个属性以及它的set方法。
2.getView(int id)方法中多了一行代码view.setOnClickListener(this);
。
3.onClick方法
这3处代码所做的只有一件事情,就是为private SparseArray<View> views
中的所有控件绑定监听器。
BaseRecyclerAdapter也有几处地方需要修改
1.添加成员变量以及它的set方法
private OnItemClickListener<T> onItemClickListener;
public void setOnItemClickListener(OnItemClickListener<T> onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
2.修改onBindViewHolder
@Override
public void onBindViewHolder(BaseRecyclerAdapter.BaseViewHolder holder, int position) {
T t = data.get(position);
holder.setT(t);
bindData(holder, t);
}
大功告成
完整代码
public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter<BaseRecyclerAdapter.BaseViewHolder> {
private OnItemClickListener<T> onItemClickListener;
//上下文环境
private Context context;
//数据集合
private List<T> data;
/**
* 刷新数据
*
* @param data
*/
public void refresh(List<T> data) {
this.data = data;
notifyDataSetChanged();
}
/**
* 添加数据
*
* @param data
*/
public void append(List<T> data) {
this.data.addAll(data);
notifyDataSetChanged();
}
public BaseRecyclerAdapter(Context context, List<T> data) {
this.context = context;
this.data = data;
}
@Override
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(getItemLayoutId(), parent, false);
return new BaseViewHolder(view);
}
@Override
public void onBindViewHolder(BaseRecyclerAdapter.BaseViewHolder holder, int position) {
T t = data.get(position);
holder.setT(t);
bindData(holder, t);
}
@Override
public int getItemCount() {
return data == null ? 0 : data.size();
}
public void setOnItemClickListener(OnItemClickListener<T> onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
/**
* 将数据绑定到itemView视图上
*
* @param holder
* @param t
*/
public abstract void bindData(BaseViewHolder holder, T t);
/**
* 子类通过重写此方法设置itemView项的布局视图
*
* @return
*/
public abstract int getItemLayoutId();
/**
* 封装 ViewHolder
*/
class BaseViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
// itemView 中的控件缓存在这里
private SparseArray<View> views;
//数据
private T t;
public BaseViewHolder(View itemView) {
super(itemView);
views = new SparseArray<>();
}
public void setT(T t) {
this.t = t;
}
/**
* 获取 itemView 中的控件
*
* @param id
* @return
*/
public View getView(int id) {
View view = views.get(id);
if (view == null) {
view = itemView.findViewById(id);
views.put(id, view);
view.setOnClickListener(this);
}
return view;
}
@Override
public void onClick(View v) {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(v, t);
}
}
}
/**
* 回调接口
* @param <T>
*/
public interface OnItemClickListener<T> {
void onItemClick(View view, T t);
}
}
使用
将MainActivity中的
//绑定监听器
adapter.setOnItemClickListener(new RecordAdapter.OnItemClickListener() {
@Override
public void onIdClick(View v, Record record) {
Toast.makeText(MainActivity.this, record.getId().toString(), Toast.LENGTH_SHORT).show();
}
@Override
public void onRemarkClick(View v, Record record) {
Toast.makeText(MainActivity.this, record.getRemark(), Toast.LENGTH_SHORT).show();
}
@Override
public void onCreationTimeClick(View v, Record record) {
Toast.makeText(MainActivity.this, record.getCreatedAt().toString(), Toast.LENGTH_SHORT).show();
}
});
替换成
//绑定监听器
adapter.setOnItemClickListener(new BaseRecyclerAdapter.OnItemClickListener<Record>() {
@Override
public void onItemClick(View view, Record record) {
switch (view.getId()) {
case R.id.tvId:
Toast.makeText(MainActivity.this, record.getId().toString(), Toast.LENGTH_SHORT).show();
break;
case R.id.tvRemark:
Toast.makeText(MainActivity.this, record.getRemark(), Toast.LENGTH_SHORT).show();
break;
case R.id.tvCreatedAt:
Toast.makeText(MainActivity.this, record.getCreatedAt().toString(), Toast.LENGTH_SHORT).show();
break;
}
}
});
运行效果自己亲自试一试就知道了。