Google推出控件RecyclerView推出以后。ListView逐渐被RecyclerView取代。
那么RecyclerView 和ListView相比有哪些优点呢?
RecylerView封装了viewholder的回收复用,也就是说RecylerView标准化了ViewHolder,编写Adapter面向的是ViewHolder而不再是View了,复用的逻辑被封装了,写起来更加简单。
高度的解耦,扩展性强,针对一个Item的显示RecylerView专门抽取出了相应的类,来控制Item的显示,使其的扩展性非常强。
可以控制Item增删的动画,可以通过ItemAnimator这个类进行控制,当然针对增删的动画,RecylerView有其自己默认的实现。
前面讲到RecylerView封装了viewholder的回收复用,在我们使用RecyclerView就会用到RecyclerView.Adapter,而每创建一个adapter就要创建一个RecyclerView.ViewHolder类,实际开发中由于会用到不止一个RecyclerView,不断重复以上步奏使得代码臃肿,实现起来非常费劲。大大的增加了程序员的代码工作量。这显然不是我们想要的。
继承RecyclerView.BaseAdapter需要实现3个抽象方法:
1. onCreateViewHolder
2. onBindViewHolder
3. getItemCount
需要一个RecyclerView.ViewHolder的实现类
其中getItemCount()可以构造方法传入数据List,直接实现。
而onCreateViewHolder则需要返回一个ViewHolder的对象,而创建ViewHolder对象需要一个子条目的根View。考虑到一个Adapter可能有多个activity用到,而布局可能不同,所以我们在构造方法中传入layoutId用来创建view。
public class SimpleQuickAdapter<B> extends RecyclerView.Adapter<SimpleQuickAdapter.SimpleViewHolder> {
private int layoutId;
protected List mData;
/**
* @param layoutId 子条目的布局
* @param list 数据
*/
public SimpleQuickAdapter(@LayoutRes int layoutId, List list) {
this.layoutId = layoutId;
this.mData = list != null ? list : new ArrayList();
}
@Override
public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindViewHolder(SimpleViewHolder holder, int position) {
}
@Override
public int getItemCount() {
return mData.size();
}
}
public class SimpleViewHolder extends RecyclerView.ViewHolder{
public SimpleViewHolder(View itemView) {
super(itemView);
}
}
我们先创建一个SimpleViewHolder类继承RecyclerView.ViewHolder作为Adapter的泛型,因为数据的类型是不确定的,我们这里也设计为泛型。
构造方法传入layoutId后,我们就可以创建ViewHolder,然后实现onCreateViewHolder方法,考虑到Context参数经常在绑定数据的时候用到,而view又能拿到context,所以我们在实现onCreateViewHolder方法的时候顺便拿到Context对象
protected Context mContext;
@Override
public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
mContext = parent.getContext();
LayoutInflater layoutInflater = LayoutInflater.from(mContext);
View view = layoutInflater.inflate(layoutId, parent, false);
SimpleViewHolder holder = new SimpleViewHolder(view);
return holder;
}
在onBindViewHolder方法中,我们可以进行数据绑定,事件监听。
数据绑定显然要交给子类去处理,我们把类改为抽象类,然后定义抽象方法。事件绑定我们就写一个最常用的字条目点击事件。
private OnItemClickListener onItemClickListener;
@Override
public void onBindViewHolder(final SimpleViewHolder holder, final int position) {
if (this.onItemClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onItemClickListener.onItemClick(SimpleQuickAdapter.this, holder.itemView, mData.get(position), position);
}
});
}
convert(holder, position, mData.get(position));
}
protected abstract void convert(SimpleViewHolder holder, int position, B b);
public interface OnItemClickListener {
void onItemClick(SimpleQuickAdapter adapter, View itemView, Object b, int position);
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
经过以上分装adapter基本上已经可以用了
但是每次用viewHolder绑定数据时,都要用holder.itemView.findViewById(viewId)找到控件后才能对控件进行操作,这就显得有点繁琐。所以我们有必要对Holder进行简单的封装。
public class SimpleViewHolder extends RecyclerView.ViewHolder {
public SimpleViewHolder(View itemView) {
super(itemView);
}
public V getView(int viewId){
return itemView.findViewById(viewId);
}
public SimpleViewHolder setText(int viewId, String text) {
TextView view = getView(viewId);
view.setText(text);
return this;
}
public SimpleViewHolder setText(@IdRes int viewId, @StringRes int strId) {
TextView view = getView(viewId);
view.setText(strId);
return this;
}
}
我们可以在这里对图片设置,背景设置,设置是否显示…等常用功能进行封装,原理差不多,就不多写了。
我们每次getView都会去访问itemView.findViewById(viewId),如果对同一控件进行多次操作就没这个必要。我们可以拿个容器去存储用过的view来提升效率。
private SparseArray views;
public SimpleViewHolder(View itemView) {
super(itemView);
this.views = new SparseArray<>();
}
//当集合views中有view时直接返回view,当集合中没有view的时候findViewById获取view,并且把这个view存入集合
public V getView(int viewId){
View view = views.get(viewId);
if (view == null) {
view = itemView.findViewById(viewId);
views.put(viewId, view);
}
return (V) view;
}
github传送门