RecyclerView简介:
谷歌在support v7中,加入了新的控件——RecyclerView,该控件整合了ListView、GridView的特点,而且最大的优点是可以很方便实现瀑布流效果,多布局控制效果等等,因此RecyclerView受到越来越多的开发者重视。
引入RecyclerView
由于该控件并不在Andorid SDK中的,而是在support v7包中,因此我们要手动添加该控件。
在build.gradle中添加如下依赖:
dependencies {
...
compile 'com.android.support:appcompat-v7:23.1.1' //Toolbar
compile 'com.android.support:recyclerview-v7:23.1.1' //RecyclerView
}
几个重要的类:
- RecyclerView.Adapter:抽象类,为RecyclerView提供数据,一般根据不同的业务需求来编写具体的实现类。
- RecyclerView.LayoutManager:抽象类,主要用于测量RecyclerView的子Item,以及根据不同的布局方式来实现Item的布局效果,v7包自带的实现类有:LinearLayoutManager、StaggeredGridLayoutManager、GridLayoutManager。
- RecyclerView.ItemDecoration:抽象类,这个主要用于不同的Item之间添加分割线(可选)。官方没有实现类,所以如果要添加分割线,我们需要手动实现这个抽象类。
- RecyclerView.ItemAnimator:抽象类,这个主要用于当一个item添加或者删除的时候出现的动画效果,官方提供一个默认的实现类。如果想要使我们的RecyclerView在添加、删除数据的时候有炫酷的动画,可以实现这个抽象类。
使用RecyclerView的主要步骤:
- 引入RecyclerView
- 添加XML布局
- 封装Adapter适配器
- 封装RecyclerView.ViewHolder类
- 实现多布局展示
- 各布局控件监听
注:在此主要实现三种不同布局加载,RecyclerView监听及子布局监听
MyAdapter类代码:
package com.example.administrator.foundationdemo.recyclerview;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import com.example.administrator.foundationdemo.R;
import java.util.List;
/**
* Created by "sinlov" on 2017/4/12.
*/
public abstract class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
private int mLayoutId;
private Context mContext;
private List<Data> mDataSet;
/**
* 构造器,接受数据集
* @param data
*/
public MyAdapter(Context context,List<Data> data){
mContext = context;
mDataSet = data;
}
/**
* onCreateViewHolder:创建ViewHolder,
* 该方法会在RecyclerView需要展示一个item的时候回调。
* 重写该方法时,应该使ViewHolder加载item view的布局。
* 这个能发避免了不必要的findViewById操作,提高了性能。
*
* @param parent
* @param viewType
* @return
*/
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//加载布局文件
switch (viewType){
case ViewItems.TEMPLATE_1:
break;
case ViewItems.TEMPLATE_2:
mLayoutId = R.layout.activity_recycler_view_recyclerview_item_my;
break;
case ViewItems.TEMPLATE_3:
break;
case ViewItems.TEMPLATE_4:
break;
case ViewItems.TEMPLATE_5:
mLayoutId = R.layout.activity_recycler_view_recyclerview_item_ordinary_notification_1;
break;
case ViewItems.TEMPLATE_6:
mLayoutId = R.layout.activity_recycler_view_recyclerview_item_ordinary_notification_2;
break;
}
MyViewHolder holder = MyViewHolder.get(mContext,null,parent,mLayoutId);
setListener(parent, holder);
return holder;
}
/**
* onBindeViewHolder:该方法在RecyclerView在特定位置展示数据时候回调,顾名思义,把数据绑定、填充到相应的item view中
*
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
//将数据填充到具体的view中
convert(holder,mDataSet.get(position));
}
public abstract void convert(MyViewHolder holder, Data t);
/**
* 通过重写getItemViewType(int position)方法来告诉onCreateViewHolder(...)每个条目对应的布局
* @param position
* @return
*/
@Override
public int getItemViewType(int position) {
return mDataSet.get(position).getViewType();
}
/**
* getItemCount:返回数据的数量
* @return
*/
@Override
public int getItemCount() {
return mDataSet.size();
}
/**
* java回调机制,依赖于子Item View的onClickListener及onLongClickListener。
* @param <T> //数据类
*/
public interface OnItemClickListener<T>{
//RecyclerView监听
void onItemClick(ViewGroup parent, View view, T t, int position);
}
public interface OnItemLongClickListener<T>{
//长按监听
boolean onItemLongClick(ViewGroup parent, View view, T t, int position);
}
private OnItemClickListener mOnItemClickListener;
private OnItemLongClickListener mOnItemLongClickListener;
public void setOnItemClickListener(OnItemClickListener mOnItemClickListener){
this.mOnItemClickListener = mOnItemClickListener;
}
public void setOnItemLongClickListener(OnItemLongClickListener mOnItemLongClickListener) {
this.mOnItemLongClickListener = mOnItemLongClickListener;
}
protected void setListener(final ViewGroup parent, final MyViewHolder holder){
//判断是否设置了监听器
if(mOnItemClickListener != null) {
//为ItemView设置监听器
holder.getConvertView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getLayoutPosition();
mOnItemClickListener.onItemClick(parent, v, mDataSet.get(position), position);
}
});
}
if(mOnItemLongClickListener != null){
holder.getConvertView().setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mOnItemLongClickListener != null) {
int position = holder.getLayoutPosition();
return mOnItemLongClickListener.onItemLongClick(parent, v, mDataSet.get(position), position);
//返回true 表示消耗了事件 事件不会继续传递
}
return false;
}
});
}
}
}
MyViewHolder类代码:
package com.example.administrator.foundationdemo.recyclerview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
/**
* Created by "sinlov" on 2017/4/13.
*/
public class MyViewHolder extends RecyclerView.ViewHolder {
private SparseArray<View> mViews;
private View mConvertView;
private Context mContext;
private int mLayoutId;
public MyViewHolder(Context context, View itemView, ViewGroup parent) {
super(itemView);
//由于itemView是item的布局文件,我们需要的是里面的textView,因此利用itemView.findViewById获
//取里面的View实例,后面通过onBindViewHolder方法能直接填充数据到每一个View了
mContext = context;
mConvertView = itemView;
//运用泛型,适配所有的View,多布局,不用写多个RecyclerView.ViewHolder。
mViews = new SparseArray<View>();
mConvertView.setTag(this);
}
//缓存
public static MyViewHolder get(Context context, View convertView,
ViewGroup parent, int layoutId){
if(null==convertView){
View itemView = LayoutInflater.from(context).inflate(layoutId, parent, false);
MyViewHolder holder = new M