前言:因为RecyclerView在项目中要经常使用,故而为了方便而封装
一,四步骤:
1,数据要使用泛型
2,数据绑定通过实现抽象方法来实现
3,ViewHolder中的View成员变量转而通过view数组来实现
4,基类里面提供常用的方法
以,上一篇文章RecyclerView+MaterialRefreshLayout为例,
上一篇链接:http://blog.csdn.net/qq_28055429/article/details/59539073
二,代码如下:
(1)先建立类BaseViewHolder 继承RecyclerView.ViewHolder,代码如下:
public class BaseViewHolder extends RecyclerView.ViewHolder {
public BaseViewHolder(View itemView) {
super(itemView);
}
}
(2)创建BaseAdapter
之前创建Adapter,主要格式如下:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>
现在BaseAdapter格式如下:(
主要里面变量为protected,因为是基类)
public abstract class BaseAdapter<T , H extends BaseViewHolder> extends RecyclerView.Adapter<BaseViewHolder> {}
然后再在里面添加代码,具体如下:
/**基类:封装RecyclerView.Adapter
* Created by maiyu on 2017/3/5.
*/
public abstract class BaseAdapter<T , H extends BaseViewHolder> extends RecyclerView.Adapter<BaseViewHolder> {
protected List<T> mDatas ; //定义List<>集合,参数为泛型
protected final Context mContext ; //上下文对象
protected final LayoutInflater mInflater ; //LayoutInflater对象
protected final int mLayoutResId ; //传入的布局id
protected OnItemClickListener listener ; //定义监听器接口
/**
* 初始化数据
* @param context
* @param datas
* @param layoutResId
*/
public BaseAdapter(Context context , List<T> datas ,int layoutResId ){
this.mDatas = datas ; //初始化List<T>数据
this.mContext = context ; //初始化上下文
this.mLayoutResId = layoutResId ;
mInflater = LayoutInflater.from(context); //获取Inflater对象
}
/**
* 创建ViewHolder
* @param parent
* @param viewType
* @return
*/
@Override
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//获取View
View view = mInflater.inflate(mLayoutResId , null , false);
return new BaseViewHolder(view , listener); //创建BaseViewHolde
}
/**
* 绑定ViewHolder
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(BaseViewHolder holder, int position) {
T t = getItem(position); //获取当前T对象
bindData(holder ,t); //绑定
}
/**
* 返回长度
* @return
*/
@Override
public int getItemCount() {
if(mDatas == null || mDatas.size() <= 0){
return 0;
}
return mDatas.size();
}
/**
* 获取当前子项
* @param position
* @return
*/
public T getItem(int position){
if(position >= mDatas.size()){
return null;
}return mDatas.get(position);
}
//定义一个抽象类型的方法
public abstract void bindData(BaseViewHolder viewHolder , T t);
//接口
public interface OnItemClickListener {
void OnClick(View view , int position);
}
//设置接口
public void setOnItemClickListener(OnItemClickListener listener){
this.listener = listener ;
}
//以下这几个方法根据需要去添加,因为上一个例子中有用到
/**
* 获取数据
* @return
*/
public List<T> getDatas(){
return mDatas;
}
/**
* 清除数据
*/
public void clearData(){
mDatas.clear();
notifyItemRangeRemoved(0,mDatas.size());
}
/**
* 添加数据
* @param datas
*/
public void addData(List<T> datas){
addData(0,datas);
}
/**
* 添加数据
* @param position
* @param datas
*/
public void addData(int position,List<T> datas){
if(datas !=null && datas.size()>0) {
mDatas.addAll(datas);
notifyItemRangeChanged(position, mDatas.size());
}
}
}
后面那几个方法因为上一个例子其他代码需要,故而添加了-------就是采用方法,如果,不需要监听器,也可以不添加;
现在BaseAdapter已经基本成形,只差添加你需要常用的相关方法了。
(3)现在要回到BaseViewHolder类中,为控件绑定id了,具体代码如下,
/**基类:BaseViewHolder继承RecyclerView.ViewHolder
* Created by maiyu on 2017/3/5.
*/
public class BaseViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
//因为不知道是什么控件,多少控件,故而用SparseArray<View>数组来存放View
private SparseArray<View> views; //存放一系列View
protected BaseAdapter.OnItemClickListener listener; //定义监听器
/**
* 初始化数据
*
* @param itemView
* @param listener
*/
public BaseViewHolder(View itemView, BaseAdapter.OnItemClickListener listener) {
super(itemView);
views = new SparseArray<View>(); //初始化数组
this.listener = listener; //初始化监听
itemView.setOnClickListener(this); //设置监听
}
/**
* 获取View
*
* @param id
* @return
*/
public View getView(int id) {
return findView(id);
}
/**
* 根据id找到View,返回泛型数据
*
* @param id
* @param <T>
* @return
*/
protected <T extends View> T findView(int id) {
//找到相应view对象
View view = views.get(id);
//若为空
if (view == null) {
//初始化该view
view = itemView.findViewById(id);
//添加到views数组中
views.put(id, view);
}
return (T) view;
}
/**
* 监听器
*
* @param view
*/
@Override
public void onClick(View view) {
if (listener != null) {
//为当前view根据布局中的相应位置设置监听
listener.OnClick(view, getLayoutPosition());
}
}
}
若无需监听,也可以去掉,现在该ViewHolder也差添加相应常用方法,
(4)现在就可以在TestActivity中,直接使用了
用方法
mRecyclerView.setAdapter(new BaseAdapter<String , BaseViewHolder>(getBaseContext(),list ,R.layout.item) {
@Override
public void bindData(BaseViewHolder viewHolder, String s) {
//找到控件并设置,
TextView textView = viewHolder.getTextView(R.id.text);
Log.d("TestActivity", s + "");
textView.setText(s);
//但是如果这里有n个控件,那么是不是需要重复这样写呢??
}
});
但是你会发现问题:
No adapter attached; skipping layout
然后再在设置完适配器之后添加如下代码就可以了
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
但是,如果有好多个控件,,,那么重复代码要好多,于是就要添加常用方法,在BaseViewHolder中添加代码如下:
(这里以按钮,图片,文本为例)
/**
* 获取TextView
* @param id
* @return
*/
public TextView getTextView(int id){
return findView(id);
}
/**
* 获取ImageView
* @param id
* @return
*/
public ImageView getImageView(int id){
return findView(id);
}
/**
* 获取Button
*/
public Button getButton(int id){
return findView(id);
}
这时代码就可以直接设置了:
viewHolder.getTextView(R.id.text).setText(s + "");
但是,你会发现,用new BaseAdapter()方法并设置参数有点复杂,好不方便,故而
可以,再创建一个基类,这里命名SimpleAdapter,继承BaseAdapter,并传入相关泛型参数,如下:
public abstract class SimpleAdapter<T> extends BaseAdapter<T , BaseViewHolder> {
public SimpleAdapter(Context context, List<T> datas, int layoutResId) {
super(context, datas, layoutResId);
}
}
这样用起来比较简单:
mRecyclerView.setAdapter(new SimpleAdapter<String>(getBaseContext(),list ,R.layout.item) {
@Override
public void bindData(BaseViewHolder viewHolder, String s) {
//写代码
viewHolder.getTextView(R.id.text).setText(s + "");
}
});
是不是简单了许多,但是突然发现在里面添加为控件添加监听器时,因为是内部类关系,数值不能传过来,于是必须定义final变量取值,
这样又多了代码了,故而
public class TSAdapter extends SimpleAdapter<String> {
public TSAdapter(Context context, List<String> datas) {
super(context, datas, R.layout.item);
}
@Override
public void bindData(BaseViewHolder viewHolder, String s) {
viewHolder.getTextView(R.id.text).setText(s + "");
}
}
于是这样多简单:
//初始化适配器
adapter = new TSAdapter( getBaseContext() ,list);
adapter.setOnItemClickListener(new BaseAdapter.OnItemClickListener() {
@Override
public void OnClick(View view, int position) {
}
});
//为RecyclerView绑定适配器
mRecyclerView.setAdapter(adapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
这样,适配器自定义就好了,这里当你别的RecyclerView控件需要设置时,是不是就不需要在创建适配器了呢?只需要创建一个执行第(5)步,即创建一个继承自SimpleAdapter,并设置数据,即可