概述
現在我們基本上不怎麼使用ListView,而是使用RecyclerView代替了,關於如何引入和基本使用RecyclerView這裏就不分享了,我們主要分享的是如何打造一個全能的適配器給RecyclerView使用。
本文的例子是一個可以添加頭部和底部的RecyclerView,我們將在BaseAdapter去處理。
思路
1,我們需要一個BaseRecyclerAdapter去繼承RecyclerView.Adapter
2,我們需要一個BaseRecyclerHolder去繼承RecyclerView.ViewHolder
3,我們有三種類型的ViewType,一個是header,一種是正常的itemView,一種是bottom
4,我們需要自己集成onClick和onLongClick兩種事件
實現
1,對於BaseRecyclerHolder,我們具體的ViewHolder使用一個簡單的注入框架來實現View的初始化,所以我們在BaseRecyclerHolder引入,具體代碼如下:
public abstract class BaseRecyclerHolder extends RecyclerView.ViewHolder {
public View itemView;
public BaseRecyclerHolder(View itemView) {
super(itemView);
this.itemView = itemView;
ButterKnife.bind(this, itemView);
}
}
需要注意的是他需要聲明爲一個獨立的java文件,不能作爲BaseRecyclerAdapter的內部類
對於onClick和onLongClick事件,我們使用泛型去實現具體的回調數據,具體代碼,他們二者比較類似
OnRecyclerViewItemLongClickListener:
public interface OnRecyclerViewItemLongClickListener<T> {
void onItemLongClick(View view, T t, int position);
}
OnRecyclerViewItemClickListener:
public interface OnRecyclerViewItemClickListener<T> {
void onItemClick(View view, T t, int position);
}
對於BaseRecyclerAdapter,我們需要重寫RecyclerView.Adapter的一些方法,首先是onCreateViewHolder方法,我們在這裏判斷需要創建的Holder的類型,一共三種,一種是header的一種是bottom的,一種是itemView的,具體代碼:
@Override
public final BaseRecyclerHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemtView;
if (viewType == ITEM_TYPE_HEADER) {
itemtView = LayoutInflater.from(App.me()).inflate(getHeaderLayout(), parent, false);
return getBottomHolder(itemtView);
} else if (viewType == ITEM_TYPE_BOTTOM) {
itemtView = LayoutInflater.from(App.me()).inflate(getBottomLayout(), parent, false);
return getHeaderHolder(itemtView);
} else if (viewType == ITEM_TYPE_CONTENT) {
itemtView = LayoutInflater.from(App.me()).inflate(getItemLayout(), parent, false);
return getHolder(itemtView);
}
return null;
}
使用final是不需要子類去重寫這個方法。
然後,我們需要在onBindViewHolder方法綁定數據的時候判斷是屬於哪一種ViewHolder,然後做不同的處理。具體代碼
public final void onBindViewHolder(BaseRecyclerHolder holder, int position) {
if (isBottomView(position)) {
converBottomHolderView(holder);
} else if (isHeaderView(position)) {
converHeaderHolderView(holder);
} else {
// 需要注意獲取數據時候開始的位置,需要減去頭部佔據的size
holder.itemView.setTag(position-mHeaderCount);
holder.itemView.setOnClickListener(this);
holder.itemView.setOnLongClickListener(this);
converHolderView(holder, mDatas.get(position-mHeaderCount), position-mHeaderCount);
}
}
這裏需要注意的一個點是我們的itemView的數據計算,他是需要減去header的數量之後纔是正確的。
完整代碼:
BaseRecyclerAdapter:
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.liweijie.design.graduation.gallery.app.App;
import com.liweijie.design.graduation.gallery.event.OnRecyclerViewItemClickListener;
import com.liweijie.design.graduation.gallery.event.OnRecyclerViewItemLongClickListener;
import com.liweijie.design.graduation.gallery.util.L;
import java.util.ArrayList;
import java.util.List;
/**
* Created by liweijie on 2016/3/28.
*
*/
public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter<BaseRecyclerHolder> implements View.OnClickListener, View.OnLongClickListener {
private List<T> mDatas = new ArrayList<>();
protected OnRecyclerViewItemClickListener<T> mOnItemClickListener;
protected OnRecyclerViewItemLongClickListener<T> mOnItemLongClickListener;
private int mHeaderCount ;//頭部View個數
private int mBottomCount ;//底部View個數
//三種類型
public static final int ITEM_TYPE_HEADER = 0;
public static final int ITEM_TYPE_CONTENT = 1;
public static final int ITEM_TYPE_BOTTOM = 2;
public BaseRecyclerAdapter(List<T> mDatas, int mHeaderCount, int mBottomCount) {
this.mDatas.addAll(mDatas);
this.mHeaderCount = mHeaderCount;
this.mBottomCount = mBottomCount;
}
@Override
public final BaseRecyclerHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemtView;
if (viewType == ITEM_TYPE_HEADER) {
itemtView = LayoutInflater.from(App.me()).inflate(getHeaderLayout(), parent, false);
return getBottomHolder(itemtView);
} else if (viewType == ITEM_TYPE_BOTTOM) {
itemtView = LayoutInflater.from(App.me()).inflate(getBottomLayout(), parent, false);
return getHeaderHolder(itemtView);
} else if (viewType == ITEM_TYPE_CONTENT) {
itemtView = LayoutInflater.from(App.me()).inflate(getItemLayout(), parent, false);
return getHolder(itemtView);
}
return null;
}
/**
*
* @param holder
* @param position
*/
@Override
public final void onBindViewHolder(BaseRecyclerHolder holder, int position) {
if (isBottomView(position)) {
converBottomHolderView(holder);
} else if (isHeaderView(position)) {
converHeaderHolderView(holder);
} else {
// 需要注意獲取數據時候開始的位置,需要減去頭部佔據的size
holder.itemView.setTag(position-mHeaderCount);
holder.itemView.setOnClickListener(this);
holder.itemView.setOnLongClickListener(this);
converHolderView(holder, mDatas.get(position-mHeaderCount), position-mHeaderCount);
}
}
@Override
public int getItemCount() {
return mDatas.size() + mHeaderCount + mBottomCount;
}
public int getContentCount() {
return mDatas.size();
}
//判斷當前item是否是HeadView
public boolean isHeaderView(int position) {
return mHeaderCount != 0 && position < mHeaderCount;
}
//判斷當前item是否是FooterView
public boolean isBottomView(int position) {
L.i("Bottom",position+"==" +(mHeaderCount+getContentCount()));
return mBottomCount != 0 && position >= (mHeaderCount + getContentCount());
}
@Override
public int getItemViewType(int position) {
int dataItemCount = getContentCount();
// 第一個
if (mHeaderCount != 0 && position < mHeaderCount) {
//頭部View
return ITEM_TYPE_HEADER;
} else if (mBottomCount != 0 && position >= (mHeaderCount + dataItemCount)) { //底部
//底部View
return ITEM_TYPE_BOTTOM;
} else {
//內容View
return ITEM_TYPE_CONTENT;
}
}
public abstract BaseRecyclerHolder getHolder(View itemtView);
/**
* 子類需要,子類實現
*
* @return
*/
public BaseRecyclerHolder getBottomHolder(View itemtView) {
return null;
}
/**
* 子類需要,子類實現
*
* @return
*/
public BaseRecyclerHolder getHeaderHolder(View itemtView) {
return null;
}
public abstract int getItemLayout();
/**
* 子類需要,子類實現
*
* @return
*/
public int getHeaderLayout() {
return 0;
}
/**
* 子類需要,子類實現
*
* @return
*/
public int getBottomLayout() {
return 0;
}
public abstract void converHolderView(BaseRecyclerHolder holder, T t, int position);
/**
* 子類需要,子類實現
*
* @return
*/
public void converBottomHolderView(BaseRecyclerHolder holder) {
}
/**
* 子類需要,子類實現
*
* @return
*/
public void converHeaderHolderView(BaseRecyclerHolder holder) {
}
// 一般操作
public void add(T t) {
mDatas.add(t);
this.notifyDataSetChanged();
}
public T get(int position) {
return mDatas.size() <= position ? mDatas.get(position) : null;
}
public List<T> getDatas() {
return mDatas;
}
// 事件相關
public void setOnItemClickListener(OnRecyclerViewItemClickListener<T> listener) {
this.mOnItemClickListener = listener;
}
public void setOnItemLongClickListener(OnRecyclerViewItemLongClickListener<T> listener) {
this.mOnItemLongClickListener = listener;
}
// 事件
@Override
public void onClick(View v) {
if (mOnItemClickListener != null) {
int position = (int) v.getTag();
mOnItemClickListener.onItemClick(v, mDatas.get(position), position);
}
}
@Override
public boolean onLongClick(View v) {
if (mOnItemLongClickListener != null) {
int position = (int) v.getTag();
mOnItemLongClickListener.onItemLongClick(v, mDatas.get(position), position);
}
return false;
}
}
這樣子,我們通過抽閒方法讓子類實現,通過一些header或者是bottom的方法,讓子類選擇實現,避免無用代碼。
使用:
public class CollectFragmentAdapter extends BaseRecyclerAdapter<ImageBean> {
public CollectFragmentAdapter(List<ImageBean> mDatas) {
super(mDatas, 1, 1);
}
@Override
public BaseRecyclerHolder getHolder(View itemtView) {
return new CollectHolder(itemtView);
}
@Override
public int getItemLayout() {
return R.layout.item_gallery_all_pic;
}
@Override
public int getHeaderLayout() {
return R.layout.core_blank_view;
}
@Override
public int getBottomLayout() {
return R.layout.core_blank_view;
}
@Override
public BaseRecyclerHolder getBottomHolder(View itemtView) {
return new CollectBottomHolder(itemtView);
}
@Override
public BaseRecyclerHolder getHeaderHolder(View itemtView) {
return new CollectHeaderHolder(itemtView);
}
@Override
public void converHolderView(BaseRecyclerHolder holder, ImageBean imageBean, int position) {
if (holder instanceof CollectHolder) {
CollectHolder localHolder = (CollectHolder) holder;
localHolder.collect_item_tv_cont.setText(String.valueOf(imageBean.getCount()));
localHolder.collect_item_tv_name.setText("" + imageBean.getName());
MyImageLoader.getInstance(2, MyImageLoader.Type.LIFO).loadImage(imageBean.getFirstImage(), localHolder.collect_item_iv_first);
}
}
class CollectHolder extends BaseRecyclerHolder {
@Bind(R.id.collect_item_iv_first)
ImageView collect_item_iv_first;
@Bind(R.id.collect_item_tv_name)
TextView collect_item_tv_name;
@Bind(R.id.collect_item_tv_cont)
TextView collect_item_tv_cont;
public CollectHolder(View itemView) {
super(itemView);
}
}
class CollectHeaderHolder extends BaseRecyclerHolder {
public CollectHeaderHolder(View itemView) {
super(itemView);
}
}
class CollectBottomHolder extends BaseRecyclerHolder {
public CollectBottomHolder(View itemView) {
super(itemView);
}
}
}
這樣子就行了,以後我們的Adapter就可以繼承這個BaseRecyclerAdapter了。
使用longclock事件:
mAdapter.setOnItemLongClickListener(new OnRecyclerViewItemLongClickListener<ImageBean>() {
@Override
public void onItemLongClick(View view, ImageBean bean, int position) {
}
});
使用click事件類似。