从Android 5.0开始,谷歌公司推出了一个用于大量数据展示的新控件RecylerView,是support-v7包中的新组件,是一个强大的滑动组件,拥有item回收复用的功能。
1、基本使用
在使用RecyclerView时候,必须指定一个适配器Adapter和适配器需要的数据源、一个布局管理器LayoutManager。
//设置数据源
List data = initData();
RecyclerView rv = (RecyclerView) findViewById(R.id.rv);
//设置布局管理器
rv.setLayoutManager(new LinearLayoutManager(this));
//设置适配器
rv.setAdapter(new NormalAdapter(data));
2、创建适配器
标准实现步骤如下:
① 创建Adapter:创建一个继承RecyclerView.Adapter的Adapter类(VH是ViewHolder的类名)
② 创建ViewHolder:在Adapter中创建一个继承RecyclerView.ViewHolder的静态内部类,记为VH。
③ 在Adapter中实现3个方法:
onCreateViewHolder()
这个方法主要生成为每个Item inflater出一个View,但是该方法返回的是一个ViewHolder。该方法把View直接封装在ViewHolder中,然后我们面向的是ViewHolder这个实例,当然这个ViewHolder需要我们自己去编写。
onBindViewHolder()
这个方法主要用于适配渲染数据到View中,滑动屏幕时,并不是销毁控件,而是修改控件显示的数据,这样效率才高,所以叫RecyclerView。
getItemCount()
这个方法提供总共有多少个条目,RecyclerView对屏幕进行管理,需要知道有多少个条目,这也算是基本要求。
3、基本的Adapter实现
public class NormalAdapter extends RecyclerView.Adapter{
public static class VH extends RecyclerView.ViewHolder{
public final TextView title;
public VH(View v) {
super(v);
title = (TextView) v.findViewById(R.id.title);
}
}
private List mDatas;
public NormalAdapter(List data) {
this.mDatas = data;
}
//③ 在Adapter中实现3个方法
@Override
public void onBindViewHolder(VH holder, int position) {
holder.title.setText(mDatas.get(position));
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//item 点击事件
}
});
}
@Override
public int getItemCount() {
return mDatas.size();
}
@Override
public VH onCreateViewHolder(ViewGroup parent, int viewType) {
//只有在setContentView()里面的layout中才能使用findViewById(),
//在运行时inflate加载的布局,不能使用findViewById(),否则会出现空指针异常,必须用View 中的findViewById(int id)
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_1, parent, false);
return new VH(v);
}
}
4、Layout Manager布局管理器
LayoutManager负责RecyclerView的布局,其中包含了Item View的获取与回收,RecyclerView提供了三种布局管理器:
-LinerLayoutManager 以垂直或者水平列表方式展示Item
-GridLayoutManager 以网格方式展示Item
-StaggeredGridLayoutManager 以瀑布流方式展示Item
-LayoutManager 常见 API
canScrollHorizontally();//能否横向滚动
canScrollVertically();//能否纵向滚动
scrollToPosition(int position);//滚动到指定位置
setOrientation(int orientation);//设置滚动的方向
getOrientation();//获取滚动方向
findViewByPosition(int position);//获取指定位置的Item View
findFirstCompletelyVisibleItemPosition();//获取第一个完全可见的Item位置
findFirstVisibleItemPosition();//获取第一个可见Item的位置
findLastCompletelyVisibleItemPosition();//获取最后一个完全可见的Item位置
findLastVisibleItemPosition();//获取最后一个可见Item的位置
5、Item Decoration间隔样式
RecyclerView通过addItemDecoration()方法添加item之间的分割线。
添加系统分割线recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
自定义间隔样式需要继承RecyclerView.ItemDecoration类,该类是个抽象类,官方目前并没有提供默认的实现类,主要有三个方法。
public class MyDecoration extends RecyclerView.ItemDecoration{
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
}
@Override
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDraw(c, parent, state);
}
@Override
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDrawOver(c, parent, state);
}
}
6、Item Animator动画
RecyclerView能够通过mRecyclerView.setItemAnimator(ItemAnimator animator)设置添加、删除、移动、改变的动画效果。
RecyclerView提供了默认的ItemAnimator实现类:DefaultItemAnimator。如果没有特殊的需求,默认使用这个动画即可。
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
7、点击事件
由于 RecyclerView 没有自带的点击事件,因此点击事件必须要由我们自己去设置,我们直接在 MyViewHolder 构造方法中为 选项对象设置点击事件即可:
public MyViewHolder(View itemView){
super(itemView);
iv_icon = (ImageView) itemView.findViewById(R.id.iv_icon);
tv_title = (TextView) itemView.findViewById(R.id.tv_title);
//添加点击事件
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext, "当前点击 "+ datas.get(getLayoutPosition()), Toast.LENGTH_SHORT).show();
}
});
}
许多时候,我们需要在activity中调用点击事件,此时需要我们在适配器里定义接口,然后回调出去即可实现我们的点击事件,在适配器里 创建内部的 接口及 回调方法 。
//点击 RecyclerView 某条的监听
public interface OnItemClickListener{
/**
* 当RecyclerView某个被点击的时候回调
* @param view 点击item的视图
* @param data 点击得到的数据
*/
void onItemClick(View view, String data);
}
private OnItemClickListener onItemClickListener;
/**
* 设置RecyclerView某个的监听
* @param onItemClickListener
*/
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
public MyViewHolder(View itemView){
super(itemView);
iv_icon = (ImageView) itemView.findViewById(R.id.iv_icon);
tv_title = (TextView) itemView.findViewById(R.id.tv_title);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Toast.makeText(mContext, "当前点击 "+ datas.get(getLayoutPosition()), Toast.LENGTH_SHORT).show();
//调用acitvity的onItemClick
if(onItemClickListener != null){
onItemClickListener.onItemClick(v, datas.get(getLayoutPosition()));
}
}
});
在acitivy中生成适配器类对象时,同时生成点击接口匿名类
adapter.setOnItemClickListener(new MyRecyclerViewAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, String data) {
Toast.makeText(MainActivity.this, "点击-> "+ data, Toast.LENGTH_SHORT).show();
}
});
8、局部刷新
RecyclerView提供了notifyItemInserted(),notifyItemRemoved(),notifyItemChanged()等API更新单个或某个范围的Item视图。
除了屏幕内显示的ViewHolder外,屏幕外后台的对列池ViewHolder最多只维持2个,在滑动过程中,只要ViewHolder还没有滑出屏幕就 不需要执行onBindViewHolder和onCreateViewHolder,后台ViewHolder只执行onBindViewHolder,只有在ViewHolder的新建时才执行onCreateViewHolder。