android v7兼容包RecyclerView的使用(二)
上篇文章 android v7兼容包RecyclerView的使用(一)讲了RecyclerView的最基本用法,现在开始挖掘更详细的内容。
在RecyclerView的API中,有这样一句话
A flexible view for providing a limited window into a large data set.
大致意思就是:当有大量的数据显示在一个有限大小的窗口上时,RecyclerView就是解决这种情况的一个灵活的View。
从以上描述可以看出RecyclerView的使用场景。如果我们有大量的同一类型的数据要显示在屏幕上,而此时很有可能整个屏幕无法完全显示所有的数据,这时候RecyclerView就是一个合适的选择。当用户上下滚动屏幕的时候,item的循环重复利用也在同时进行,当一个新的item进入可视范围,必然有一个旧的item移出可视范围,而这个被移出的item也就被循环重用。那么循环重用item有什么作用呢,其实他是很有用的一种方法,因为它节省了CPU资源和内存。
或许你会说我们用ListView用了很长的时间了,RecyclerView与我们以前的方式有什么特别的地方呢,从前,我们使用listview的时候,显示,循环重用以及其它的一些东西都有一定程度上的耦合性,现在RecyclerView则提供了一种更加灵活的方式。
谷歌现在使用的这种方法,它不在乎RecyclerView所看到的东西,也不在乎元素是否显示在正确的地方,更不在乎每个元素是如何分隔的。RecyclerView做的事仅仅是是回收。因此得名RecyclerView。
下面是几个和RecyclerView有关的最重要的类
Adapter:适配器,绑定数据集
ViewHolder:根据当前的数据保存视图
LayoutManager:布局管理器。决定item如何摆放
ItemDecoration:勉强理解为item装饰器,可以美化item
ItemAnimator:动画,当一个item被增加,删除或者重新摆放时,会有动画效果。
ViewHolder
安卓官方已经推荐使用ViewHolder模式有很长一段时间了,因为它能在一定程度上大大提高效率,界面流畅性增加。RecyclerView的适配器是一个内部类,我们通过继承它来扩展我们的子类,就像这样。
public final static class ListItemViewHolder extends RecyclerView.ViewHolder {
TextView title;//item界面上的一个元素
TextView description;//item界面上的一个元素
//当然可以继续增加这些元素
public ListItemViewHolder(View itemView) {
super(itemView);
//关联引用
title= (TextView) itemView.findViewById(R.id.title);
description= (TextView) itemView.findViewById(R.id.description);
}
}
RecyclerView.Adapter
适配器完成两个主要功能:负责建立基础数据集和单个item布局之间的联系。适配器是Android的一个重要部分之一。它被用在许多地方,比如ListView, AutoCompleteTextView, Spinner都用到了适配器。
谷歌使用了RecyclerView的内部类Adapter代替了传统的Adapter,所以在RecyclerView中,你不会见到类似SimpleCursorAdapter, ArrayAdapter这样的适配器。
然而不幸的是谷歌并没有提供RecyclerView.Adapter的默认实现类,它是一个抽象类,所以我们必须去实现三个方法。
public VH onCreateViewHolder(ViewGroup parent, int viewType)
public void onBindViewHolder(VH holder, int position)
public int getItemCount()
VH是一个继承自ViewHolder的泛型,在子类中必须提供具体的类型。最基本的适配器写法如下
public class RecyclerViewAdapter extends
RecyclerView.Adapter
<RecyclerViewAdapter.ItemViewHolder> {
private List<DemoModel> items;
RecyclerViewAdapter(List<DemoModel> modelData) {
if (modelData == null) {
throw new IllegalArgumentException(
"modelData must not be null");
}
this.items = modelData;
}
@Override
public ItemViewHolder onCreateViewHolder(
ViewGroup viewGroup, int viewType) {
View itemView = LayoutInflater.
from(viewGroup.getContext()).
inflate(R.layout.item,viewGroup,false);
return new ItemViewHolder(itemView);
}
@Override
public void onBindViewHolder(
ItemViewHolder viewHolder, int position) {
DemoModel model = items.get(position);
viewHolder.title.setText(model.getTitle());
viewHolder.description.setText(model.getDescription());
}
@Override
public int getItemCount() {
return items.size();
}
public final static class ItemViewHolder
extends RecyclerView.ViewHolder {
// ... shown above in the ViewHolder section
}
}
RecyclerView.LayoutManager
布局管理器是RecyclerView最有意思的一个地方,它负责对所有子item进行布局,在最新的v7兼容库中,它有三个实现类,分别是LinearLayoutManager(线性布局),GridLayoutManager(a网格布局),StaggeredGridLayoutManager(流式布局),默认情况下,如果我们不设置布局管理器,将使用线性布局。我们可以通过继承该类实现自己的布局管理器,由我们自己决定如何摆放item的内容,然而,当你去看上面的三个实现类的代码时,你会发现这是多么不容易的一件事。。。代码好长。。。真的!布局管理器的具体使用方法将再开一篇博客,这里先介绍一下线性布局管理器的简单使用。代码如下
//实例化对象
LinearLayoutManager layoutManager = new LinearLayoutManager(context);
//设置布局方向为竖直
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
//滚动到那一项
layoutManager.scrollToPosition(currPos);
//设置布局管理器
recyclerView.setLayoutManager(layoutManager);
RecyclerView.ItemDecoration
姑且我叫它为item装饰器,使用ItemDecoration我们可以给item增加偏移量,增加item分割线,高亮等等。我们可以能增加很多个ItemDecoration,RecyclerView 会依次遍历所有的ItemDecoration并调用绘图方法去完成装饰。它有三个抽象方法
public void onDraw(Canvas c, RecyclerView parent)
public void onDrawOver(Canvas c, RecyclerView parent)
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent)
在onDraw中绘制的内容可能会被item的内容遮挡,但是你在onDrawOver中绘制的内容会被绘制在item上方。我们可以使用偏移量对item进行简单分割,但是如果你想显示一条分割线,你就不得不去使用onDrawOver方法去显式的绘制一条分隔线。
布局管理器会在测量阶段调用getItemOffset方法,它与一个Rect类型的参数,outRect 参数看上去有点怪怪的,那么为什么不用一个返回值代替它呢,既然谷歌这样做了,必然是有意义的。因为这样可以让所有item去复用一个Rect对象因此节约了资源,这样做不一定是最好的,但是的确可以有效节约资源。
有一点要值得注意的是,onDraw()/onDrawOver()方法并不会为每个item调用,它只会被调用一次去绘制所有item的装饰内容。因此我们必须在该方法中遍历所有item进行绘制。
上篇文章简单提供了一个DividerItemDecoration的源码,当然我们可以通过继承ItemDecoration 去实现更加丰富的内容。
RecyclerView.ItemAnimator
ItemAnimator类主要是处理动画效果,以下三种情况,会触发该动画。
- 一个item被添加到数据集中
- 一个item从数据集中被移除
- 一项在界面中位置被移动了
幸运的是,在v7兼容包中提供了一个默认的实现类叫做DefaultItemAnimator,如果我们不设置,默认就会适应该类。
如果想让动画生效,很明显android必须知道数据改变了。在早期的适配器中,我们需要调用notifyDataSetChanged方法通知android数据集改变了。但是现在不再适用了,这个方法会重绘所有可见item但是不会触发任何动画,我们必须调用类似以下的方法才能触发动画。
public final void notifyItemInserted(int position)
public final void notifyItemRemoved(int position)
Listeners
监听器,RecyclerView中不再有OnItemClickListener和OnItemLongClickListener监听器,但是我们可以使用OnItemTouchListener再配合手势去识别这些事件,这意味着我们需要编写更多的代码去实现同样的效果。
综上所述
在布局文件中使用,代码如下
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:listitem="@layout/item_demo_01"
/>
tools属性会渲染当前布局,当我们切换到可视化编辑器的时候可以看到效果,当然也可以不写,只是看不到效果罢了。
我们可以看到,并没有使用一些特别的属性,实际上RecyclerView的属性都是来自其父类ViewGroup。在RecyclerView中有一个方法用到了AttributeSet,这个方法就是generateLayoutParams,但是在内部它也并没有怎么对属性进行操作。
@Override
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
if (mLayout == null) {
throw new IllegalStateException("RecyclerView has no LayoutManager");
}
return mLayout.generateLayoutParams(getContext(), attrs);
}
而在Activity中使用它也是很简单的
//获得控件引用
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
//实例化布局管理器并设置布局管理器,滚动到顶部
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
layoutManager.scrollToPosition(0);
recyclerView.setLayoutManager(layoutManager);
// 当item大小一样时有利于优化,具体怎么个优化法我也不知道。。
recyclerView.setHasFixedSize(true);
// 绑定适配器并提供数据集
List<DemoModel> items = new ArratList<DemoModel>();
//......这里进行数据的初始化工作
adapter = new RecyclerViewDemoAdapter(items);
recyclerView.setAdapter(adapter);
//使用装饰器,该类的源码在上一篇文章中有提供
RecyclerView.ItemDecoration itemDecoration =
new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST);
//注意这里是add而不是set,说明可以添加多个
recyclerView.addItemDecoration(itemDecoration);
// 下面这句话可以不写,因为默认就是使用该类;
// 当我们自定义了动画,才有必要去设置
recyclerView.setItemAnimator(new DefaultItemAnimator());
// 设置监听器,需要配合手势
//recyclerView.addOnItemTouchListener(this);
总结为以下几步
- 获得RecyclerView引用
- 创建布局管理器并添加到RecyclerView中
- 创建适配器并添加到RecyclerView中
- 创建0到多个item装饰器ItemDecoration,前提是有必要的话
- 创建ItemAnimator,如果有必要的话
- 创建0到多个监听器并增加到RecyclerView中
基本源码同上篇文章,源码下载地址http://download.csdn.net/detail/sbsujjbcy/8489667
本篇文章参考了http://www.grokkingandroid.com/first-glance-androids-recyclerview/
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。