设计步骤:
- 封装ViewHodler类
- 封装RecycleView.Adapter类,编写公共逻辑和方法。
- 进一步提升通用性,添加多Item类型支持
封装ViewHolder
每次写Adapter的时候总会依赖一个ViewHodler类,也是挺麻烦的事,虽说只要继承一下系统的ViewHolder
但是如果控件比较多,那还是一种很苦恼的事。
- 设计思路
每个ViewHodler都需要依赖一个View,所有的子控件都是从这个View中获取。因此我们可以不必定义好那么多子控件,只需要用到的时候去拿就行。直接上代码:
public final class RecycleViewHolder extends RecyclerView.ViewHolder {
private SparseArray<View> views;
private RecycleViewHolder(@NonNull View itemView) {
super(itemView);
views=new SparseArray<>();
}
/**
* 创建ViewHolder
* @param context 上下文
* @param parent 父View
* @param layoutId 布局Id
* @return 返回ViewHolder
*/
public static RecycleViewHolder get(@NonNull Context context,@NonNull ViewGroup parent,@LayoutRes int layoutId){
View itemView=LayoutInflater.from(context).inflate(layoutId,parent,false);
return new RecycleViewHolder(itemView);
}
public <T extends View>T getView(int id){
View view=views.get(id);
if(view==null){
view=itemView.findViewById(id);
views.put(id,view);
}
return (T) view;
}
public View getItemView() {
return itemView;
}
}
代码很少,直接看关键方法public <T extends View>T getView(int id)
,该方法负责从ItemView
中获取子控件,控件只需要获取一次就好,因此这里加入了缓存SparseArray
,如果已经存在就不再去findViewById
了。
封装RecycleView.Adapter类
- 设计思路
每个Adapter都需要依赖一个集合数据,以及Item布局和类型,还有它的ViewHolder,这些都是公共的。变化的只是在onBindViewHolder
中的内容。- 集合数据好弄,我们只需要利用泛型功能即可。
- Item布局和类型,利用接口,让使用者提供即可。
- ViewHolder就是我们上面封装的通用ViewHodler。
- onBindViewHolder中内容,抽象出来让使用者自己实现。
public class EasyRecyclerViewAdapter<T> extends RecyclerView.Adapter<RecycleViewHolder> {
private Context mContext;
private List<T> datas;
private MutliItemType<T> mutliItemTypeSupport;
private OnItemClickListener<T> onItemClickListener;
private OnItemLongClickListener<T> onItemLongClickListener;
private OnBindView<T> onBindView;
/**
* 单布局构造器
* @param mContext 上下文
* @param datas 数据集合
* @param layoutId 布局Id
*/
public EasyRecyclerViewAdapter(Context mContext, List<T> datas,@LayoutRes int layoutId) {
this(mContext,datas,itemType -> layoutId);
}
/**
* 多布局支持构造器
* @param mContext 上下文
* @param datas 集合数据
* @param mutliItemTypeSupport {@link MutliItemType} 接口
*/
public EasyRecyclerViewAdapter(Context mContext, List<T> datas, MutliItemType<T> mutliItemTypeSupport) {
this(mContext,datas,mutliItemTypeSupport,null);
}
/**
* 多布局支持构造器
* @param mContext 上下文
* @param datas 集合数据
* @param mutliItemTypeSupport {@link MutliItemType} 接口
* @param bindView {@link OnBindView}视图数据绑定接口
*/
public EasyRecyclerViewAdapter(Context mContext, List<T> datas, MutliItemType<T> mutliItemTypeSupport,OnBindView<T> bindView) {
this.mContext = mContext;
this.datas = datas;
this.mutliItemTypeSupport = mutliItemTypeSupport;
this.onBindView=bindView;
}
@NonNull
@Override
public RecycleViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int itemType) {
int layout=mutliItemTypeSupport.getLayout(itemType);
return RecycleViewHolder.get(mContext,viewGroup,layout);
}
@Override
public void onBindViewHolder(@NonNull RecycleViewHolder recycleViewHolder, int position) {
T data=datas.get(position);
if(onItemClickListener!=null){
recycleViewHolder.getItemView().setOnClickListener(v ->
onItemClickListener.onItemClicked(recycleViewHolder,data,position));
}
if(onItemLongClickListener!=null){
recycleViewHolder.getItemView().setOnLongClickListener(v ->
onItemLongClickListener.onItemLongClicked(recycleViewHolder,data,position));
}
if(onBindView!=null){
onBindView.bind(recycleViewHolder,data,getItemViewType(position));
}
}
@Override
public int getItemCount() {
return datas==null?0:datas.size();
}
@Override
public int getItemViewType(int position) {
return mutliItemTypeSupport.getItemViewType(position,datas==null?null:datas.get(position));
}
/*get/set ...*/
public void setOnItemClickListener(OnItemClickListener<T> onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
public OnItemClickListener<T> getOnItemClickListener() {
return onItemClickListener;
}
public MutliItemType<T> getMutliItemTypeSupport() {
return mutliItemTypeSupport;
}
public void setMutliItemTypeSupport(MutliItemType<T> mutliItemTypeSupport) {
this.mutliItemTypeSupport = mutliItemTypeSupport;
}
public OnBindView<T> getOnBindView() {
return onBindView;
}
public void setOnBindView(OnBindView<T> onBindView) {
this.onBindView = onBindView;
}
public OnItemLongClickListener<T> getOnItemLongClickListener() {
return onItemLongClickListener;
}
public void setOnItemLongClickListener(OnItemLongClickListener<T> onItemLongClickListener) {
this.onItemLongClickListener = onItemLongClickListener;
}
/**
* 多Item支持接口
* @param <T>
*/
public interface MutliItemType<T>{
@LayoutRes int getLayout(int itemType);
default int getItemViewType(int position,T data){
return 0;
}
}
public interface OnItemClickListener<T>{
void onItemClicked(RecycleViewHolder holder,T data,int position);
}
public interface OnItemLongClickListener<T>{
boolean onItemLongClicked(RecycleViewHolder holder,T data,int position);
}
/**
* {@link this.onBindViewHolder} 转换接口,用来绑定自己的试图数据以及其他逻辑
* @param <T>
*/
public interface OnBindView<T>{
void bind(RecycleViewHolder holder,T data,int itemType);
}
}
用过RecycleView
的人对上面的代码一定不陌生。
MutliItemType
接口中定义了两个方法:
-
@LayoutRes int getLayout(int itemType);
该方法用来确布局定Layout -
default int getItemViewType(int position,T data)
该方法用来确定item类型
有了这个接口剩下的事就好办多了。重写父类的onCreateViewHolder
和getItemViewType
方法。
onCreateViewHolder
该方法用来确定ViewHodler,在上面的实现中一目了然,通过MutliItemType
接口,获取LayoutId,然后使用通用ViewHodler 去创建出来。
getItemViewType
该方法用来告诉RecycleView
当前是哪个Item类型。
如次我们就能知道该创建那个布局,该绑定那个ViewHodler。