Android-RecylerView初识

今年Google I/0大会,Google开放了两个全新的视图:RecyclerView和CardView。这篇博客会提供关于RecylerView的简介。

RecylerView作为support-library发布出来,这对开发者来说绝对是个好消息。因为可以在更低的Android版本上使用这个新视图。下面我们看如何获取RecylerView。首先打开Android SDK Manager,然后更新Extras->Android Support Library即可。

Android-RecylerView初识_第1张图片

然后在本地../sdk/extras/android/support/v7中找到recyclerview。我已经将下载好的Recyclerview整理成一个Eclipse可编译的Library工程上传到Github,有需求的同学请戳链接


示例程序

我将通过RecylerView制作一个横向滑动的“ListView”,下面是示例程序的截图。并在ActionBar上设置数据的添加/删除操作。请同学们注意,RecyclerView的接口Google可能会继续优化和修改,所以最终的版本可能和我提供的程序有出入。Demo程序Github链接

Android-RecylerView初识_第2张图片


为什么要使用RecyclerView?

Google在是这样描述RecyclerView的:

"A flexible view for providing a limited window into a large data set."

所以RecyclerView适用于无法在一个屏幕范围内展现格式一样的数据时,需要用多行或多列来展示。例如展示联系人,图片,视频等。用户需要滑动屏幕来查看数据,这时RecyclerView的特性就有用武之地了。比如,当用户滑动使当前一个可视的Item滑出屏幕,这个Item的视图将会被回收并在一个新Item进入可视范围后重新被使用。

如下图所示,用户滑动向上滑动左边的RecyclerView,No.0和No.1就会滑出屏幕可视范围,这时右图的No.0和No.1的视图将会被RecyclerView放入一个可重复利用的缓存中以备再次使用。

Android-RecylerView初识_第3张图片

可回收利用View是个很实用的功能,它不仅可以减少CPU不断inflate View的开销,而且可以节省缓存View的内存开销。

这时,你可能会问:这不是一个新功能啊!是的,我们已经在使用ListView的时候使用了这个机制,但是当使用ListView时,显示,回收等功能是紧密耦合在一起的,Google现在发布RecyclerView,使方法更灵活,开发者也能自定义各种各样的显示效果。


RecyclerView不再负责显示工作

和ListView不一样的是,RecyclerView不再负责Item的摆放等显示方面的功能。所有和布局、绘制等方面的工作Google都其拆分成不同的类进行管理。所以开发者可以自定义各种各样满足定制需求的的功能类。

下面是一些和RecyclerView相关的非常重要的类列表。

RecyclerView相关类
类名
说明
RecyclerView.Adapter

托管数据集合,为每个Item创建视图

RecyclerView.ViewHolder 承载Item视图的子视图
RecyclerView.LayoutManager 负责Item视图的布局
RecyclerView.ItemDecoration 为每个Item视图添加子视图,在Demo中被用来绘制Divider
RecyclerView.ItemAnimator 负责添加、删除数据时的动画效果


ViewHolder

关于ViewHolder,Google早就推荐开发者使用,但也只是建议。但是现在,RecyclerView.Adapter最终要求开发者必须使用ViewHolder。如果你还对ViewHolder不了解,请阅读Android training session
Demo通过继承RecyclerView.ViewHolder来实现自定义:

[java]  view plain copy
  1. public class MyViewHolder extends ViewHolder implements OnClickListener,OnLongClickListener{  
  2.   
  3.     public ImageView iv;  
  4.     public TextView tv;  
  5.     private MyItemClickListener mListener;  
  6.     private MyItemLongClickListener mLongClickListener;  
  7.       
  8.     public MyViewHolder(View rootView,MyItemClickListener listener,MyItemLongClickListener longClickListener) {  
  9.         super(rootView);  
  10.         iv = (ImageView)rootView.findViewById(R.id.item_iv);  
  11.         tv = (TextView)rootView.findViewById(R.id.item_tv);  
  12.         this.mListener = listener;  
  13.         this.mLongClickListener = longClickListener;  
  14.         rootView.setOnClickListener(this);  
  15.         rootView.setOnLongClickListener(this);  
  16.     }  
  17.   
  18.     /** 
  19.      * 点击监听 
  20.      */  
  21.     @Override  
  22.     public void onClick(View v) {  
  23.         if(mListener != null){  
  24.             mListener.onItemClick(v,getPosition());  
  25.         }  
  26.     }  
  27.   
  28.     /** 
  29.      * 长按监听 
  30.      */  
  31.     @Override  
  32.     public boolean onLongClick(View arg0) {  
  33.         if(mLongClickListener != null){  
  34.             mLongClickListener.onItemLongClick(arg0, getPosition());  
  35.         }  
  36.         return true;  
  37.     }  
  38.   
  39. }  


RecyclerView.Adapter

Adapter负责扮演两个角色:不仅为底部数据提供支持而且还负责为数据创建合适的视图。Adapter适用在Android很多控件,例如ListView、AutoCompleteTextView等。
继承RecyclerView.Adapter需要实现以下三个方法:

  • public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType)
  • public void onBindViewHolder(ViewHolder holder,int position)
  • public int getItemCount()
Demo中的Adapter:

[java]  view plain copy
  1. public class MyAdapter extends Adapter {  
  2.   
  3.     private List mData;  
  4.     private MyItemClickListener mItemClickListener;  
  5.     private MyItemLongClickListener mItemLongClickListener;  
  6.       
  7.     public MyAdapter(List data){  
  8.         this.mData = data;  
  9.     }  
  10.       
  11.     @Override  
  12.     public int getItemCount() {  
  13.         return mData.size();  
  14.     }  
  15.   
  16.       
  17.     @Override  
  18.     public void onBindViewHolder(MyViewHolder holder, int position) {  
  19.         MyItemBean bean = mData.get(position);  
  20.         holder.tv.setText(bean.tv);  
  21.     }  
  22.   
  23.     @Override  
  24.     public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  
  25.         View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent,false);  
  26.         MyViewHolder vh = new MyViewHolder(itemView,mItemClickListener,mItemLongClickListener);  
  27.         return vh;  
  28.     }  
[java]  view plain copy
  1. }  

onCreateViewHolder中负责为Item创建视图,onBindViewHolder负责将数据绑定到Item的视图上。


RecyclerView.LayoutManager

LayoutManager是RecyclerView中最有意思的类。该类负责将每个Item视图在RecylerView中的布局。目前Google提供了LayoutManager的一个子类:LinearLayoutManager。LinearLayoutManager提供了横向和竖向两种布局,Demo就是使用LinearLayoutManger的横向布局实现的。

如果要自定义LayoutManager,需要实现一个abstract方法

  • public LayoutParams generateDefaultLayoutParams()
Demo中为RecylerView添加LinearLayoutManager的片段:

[java]  view plain copy
  1. MyLayoutManager manager = new MyLayoutManager(this);  
  2.         manager.setOrientation(LinearLayout.HORIZONTAL);//默认是LinearLayout.VERTICAL  
  3.         mRecyclerView.setLayoutManager(manager);  
LinearLayoutManager提供了如下几个方法来帮助开发者获取屏幕上的顶部item和底部item:

  • findFirstVisibleItemPosition()
  • findFirstCompletelyVisibleItemPosition()
  • findLastVisibleItemPosition()
  • findLastCompletelyVisibleItemPosition()


RecyclerView.ItemDecoration

通过ItemDecoration可以使各个Item在视觉上相互分开,其实和ListView的Divider很像。ItemDecoration并不是RecyclerView必须设置的,开发者可以不设置或者设置多个Decoration。RecyclerView会遍历所有的ItemDecoration并调用各自的绘图方法。

继承ItemDecoration需要实现以下三个方法:

  • public void onDraw(Canvas c,RecyclerView parent,RecyclerView.State state)
  • public void getItemOffset(Rect outRect,int itemPosition,RecyclerView parent)
LayoutManager会调用getItemOffset方法来计算每个Item的Decoration合适的尺寸。

Demo中自定义了一个ItemDecoration来实现ListView的Divider效果:

[java]  view plain copy
  1. public class MyDecoration extends ItemDecoration {  
  2.   
  3.     private static final int[] ATTRS = new int[]{  
  4.         android.R.attr.listDivider  
  5.     };  
  6.       
  7.     private Drawable mDivider;  
  8.       
  9.     public MyDecoration(Context ctx){  
  10.         final TypedArray a = ctx.obtainStyledAttributes(ATTRS);  
  11.         mDivider = a.getDrawable(0);  
  12.     }  
  13.       
  14.     @Override  
  15.     public void onDraw(Canvas c, RecyclerView parent, State state) {  
  16.         int top = parent.getPaddingTop();  
  17.         int bottom = parent.getHeight() - parent.getPaddingBottom();  
  18.         int childCount = parent.getChildCount();  
  19.         for(int i=0;i < childCount;i++){  
  20.             View child = parent.getChildAt(i);  
  21.             RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams)child.getLayoutParams();  
  22.             int left = child.getRight() + layoutParams.rightMargin;  
  23.             int right = left + mDivider.getIntrinsicWidth();  
  24.             mDivider.setBounds(left, top, right, bottom);  
  25.             mDivider.draw(c);  
  26.         }  
  27.     }  
  28.       
  29.     @Override  
  30.     public void getItemOffsets(Rect outRect, View view, RecyclerView parent,  
  31.             State state) {  
  32.         outRect.set(00, mDivider.getIntrinsicWidth(), 0);  
  33.     }  
  34.       
  35. }  

RecyclerView.ItemAnimatior

当Item有以下三种操作时ItemAnimatior会为RecyclerView提供动画效果:

  • 删除某一个Item
  • 添加一个新的Item
  • 移动某个Item
Google提供了一个名为DefaultItemAnimator的默认ItemAnimator供开发者使用。如果开发者不为RecyclerView设置ItemAnimator,RecyclerView也会使用默认的DefaultItemAnimator。
显然,为了让动画效果起效,开发者必须通知Adapter数据有改变。之前我们使用Adapter时会调用notifyDataSetChanged()来通知Adapter数据改变并更新视图,现在RecyclerView,Adapter提供了许多notifyXyz()方法,例如Demo中使用了以下两个方法:

  • public final void notifyItemInserted(int position)
  • public final void notifyItemRemoved(int position)


使用RecyclerView

首先,我们先看如何在xml中使用RecyclerView

[html]  view plain copy
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     tools:context="com.xmy.recylerviewdemo.MainActivity" >  
  6.   
  7.     <android.support.v7.widget.RecyclerView  
  8.         android:id="@+id/recyclerView"  
  9.         android:layout_width="wrap_content"  
  10.         android:layout_height="wrap_content"/>  
  11.           
  12. RelativeLayout>  
然后需要开发者在代码中实现RecyclerView的组装,大体可概括为以下步骤:

  • 实例化RecyclerView
  • 为RecyclerView设置LayoutManager
  • 为RecyclerView设置Adapater
  • 如果有需求,可以设置一个或多个ItemDecorations,当然,也可以不设置
  • 如果有需求,可以设置ItemAnimator

以上就是对RecyclerView的基本介绍,下篇博客会讲RecyclerView如何像ListView一样为Item设置交互监听。


参考资料:

A First Glance at Android’s RecyclerView

你可能感兴趣的:(Android-RecylerView初识)