Android RecyclerView 使用全解析

概述

RecyclerView出来已经很长时间了,关于其的介绍也非常的多.作为ListView的升级版,它更加强大和灵活.
可以轻松的实现各种布局和动画,见其名,知其意.RecyclerView用于在有限窗口中展示大量数据集合的可复用的视图.
这里主要梳理一下Recyclerview的常用方法,示例Demo:BoBoMEe/AndroidDev

相关类

RecyclerView的灵活性,主要体现在各个类的职责分离上,
RecyclerView不负责子View的展示与布局,只负责子view的回收与复用.其他的比如,子View的布局,装饰及动画都交由其他类来处理.

RecyclerView相关类及其作用

用途
RecyclerView.ViewHolder 装载子view数据的容器
RecyclerView.LayoutManager 布局管理器,负责子View的布局
RecyclerView.Adapter 适配器,负责处理数据与绑定视图
RecyclerView.ItemDecoration 装饰子view,如分割线、偏移等
RecyclerView.ItemAnimator 子view改变时的动画

基本使用

RecyclerView最简单的使用需要设置LayoutManagerAdapter,其他的都是可选项.简单使用流程可分为以下几步.

  • 引入
1
compile 'com.android.support:recyclerview-v7:23.4.0'
1
2
3
4
5
6
7
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/item_margin"
android:clipToPadding="false"/>

  • 设置AdapterLayoutManager
1
2
3
4
5
6
7
RecyclerView mRecyclerView = (RecyclerView)findViewById(R.id.recycler_view);

mLinearLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLinearLayoutManager);

mRecyclerStringAdapter = new RecyclerStringAdapter(Datas.getDatas());
mRecyclerView.setAdapter(mRecyclerStringAdapter);

其中LinearLayoutManager代表线性显示.默认是方向为VERTICAL,LayoutManager抽象类有三个官方实现版本,分别是LinearLayoutManager(线性布局),GridLayoutManager(网格布局),StaggeredGridLayoutManager(瀑布流布局).

  • Adapter

不同于ListViewAdapter,Recyclerview的适配器强制使用ViewHolder模式.如下一个简单的Adapter实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class RecyclerStringAdapter extends RecyclerView.Adapter<RecyclerViewholder> {

List<String> datas;
public RecyclerStringAdapter(List<String> datas) {
this.datas = datas;
}

@Override public void onBindViewHolder(RecyclerViewholder holder, int position) {
holder.textView.setText(datas.get(position));
}

@Override public RecyclerViewholder onCreateViewHolder(ViewGroup parent, int viewType) {

View view =
LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item, parent, false);

return new RecyclerViewholder(view);
}

@Override public int getItemCount() {
return datas.size();
}
}

# RecyclerViewholder
public class RecyclerViewholder extends RecyclerView.ViewHolder {

public TextView textView;

public RecyclerViewholder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.text);
}
}

其他用法

  • LayoutManager布局切换

我们知道LayoutManager主要负责子View的布局.通过设置不同的LayoutManager即可实现展现方式的改变.
如果不设置LayoutManager,数据将不会展现出来.

1
2
3
//gridview的列数为3,orientation = VERTICAL
mGridLayoutManager = new GridLayoutManager(this, 3);
mRecyclerView.setLayoutManager(mGridLayoutManager);
1
2
3
4
// 瀑布流的列数为3,orientation = VERTICAL
mStaggeredGridLayoutManager =
new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(mStaggeredGridLayoutManager);
1
2
int orientation = mLinearLayoutManager.getOrientation();
mLinearLayoutManager.setOrientation(orientation == LinearLayoutManager.VERTICAL ? LinearLayoutManager.HORIZONTAL: LinearLayoutManager.VERTICAL);
  • LayoutManager常用方法
1
2
3
4
5
6
7
8
//返回当前第一个可见 Item 的 position
findFirstVisibleItemPosition()
//返回当前第一个完全可见 Item 的 position
findFirstCompletelyVisibleItemPosition()
//返回当前最后一个可见 Item 的 position
findLastVisibleItemPosition()
//返回当前最后一个完全可见 Item 的 position.
findLastCompletelyVisibleItemPosition()
  • ItemAnimatorItem动画

用于设置子view的添加、移动、删除的相关动画效果.官方默认提供了一个DefaultItemAnimator,如果我们没有设置ItemAnimator,则默认就是DefaultItemAnimator,Recyclerview.Adapter提供了notifyDataSetChanged()notifyItemInserted(index)notifyItemRemoved(position)notifyItemChanged(position)方法来刷新Recyclerview.这里可以看一下wasabeef/recyclerview-animators:实现了多种Recyclerview的Item动画

  • ItemDecorationItem装饰

通过mRecyclerView.addItemDecoration(new MarginDecoration(this));来给Item添加装饰,

ItemDecoration可以叠加,Recyclerview展示的时候会遍历所有的ItemDecoration并调用其绘制方法来对Item进行装饰.

ItemDecoration提供了三个方法用于定制装饰器:

1
2
3
4
5
6
// 在Item条目绘制之前调用,如果不是指offset则被Item的内容所遮挡
public void onDraw(Canvas c, RecyclerView parent);
// 在Item条目绘制之后调用,浮于Item之上
public void onDrawOver(Canvas c, RecyclerView parent);
// 计算并设置Item偏移量
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent);

Recyclerview多种布局

ListView中为了实现多种布局,我们需要重写Adapter中的 getItemViewTypegetViewTypeCount方法
而在Recyclerview中保留了getItemViewType方法,同时我们可以在onCreateViewHolder中根据不同的ViewType来创建不同的Holder
这里可以看一下hongyangAndroid/baseAdapter:万能的Adapter for ListView,RecyclerView,GridView
其中关于HeaderViewFooterwView的处理,同样也是通过ViewType来实现的,
在网格布局中,依靠了GridLayoutManager#setSpanSizeLookup方法来设置每个Item占多少个span,
在瀑布流不居中,通过给StaggeredGridLayoutManager.LayoutParams设置setFullSpan(true);来占满一行.

ItemTouchHelper

用于Recyclerview的触摸辅助操作,比如选中,移动,删除等事件的监听.
这里可以看一下: 可拖拽的RecyclerView,通过跟踪代码我们可以看到,ItemTouchHelper内部
主要是通过GestureDetectorCompat来处理触摸事件,并通过给Recyclerview设置OnItemTouchListener来实现效果
但是遗憾的是其中只 实现了onLongPress的监听.但是为我们设置Recyclerview的Item监听提供了一种新的思路

1
2
3
4
5
6
7
8
9
10
11
12
13
//ItemTouchHelper#ItemTouchHelperGestureListener
private class ItemTouchHelperGestureListener extends GestureDetector.SimpleOnGestureListener {

@Override
public boolean onDown(MotionEvent e) {
return true;
}

@Override
public void onLongPress(MotionEvent e) {
//...
}
}

通过ItemTouchHelper实现RecyclerviewClick,LongClick,Select,Swipe,Drag等效果,
主要通过一个叫做ItemTouchHelper.Callback的类,示例:RvItemTouchHelperCallback

Recyclerview 选中模式

遗憾的是Recyclerview并不像Listview那样提供selectMode,但是在我们最初不适用selectMode的时候,我们是否采用过一种通过刷新Adapter来实现的方式呢
Recyclerview中要实现选中模式,我们当然也要从Adapter下手,这里可以看一下Multi-Selection Mode for RecyclerView
其中的核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private SparseBooleanArray mSelectedItems;

public void switchSelectedState(int position) {
if (mSelectedItems.get(position)) { // item has been selected, de-select it.
mSelectedItems.delete(position);
} else {
mSelectedItems.put(position, true);
}
notifyItemChanged(position);
}

public void clearSelectedState() {
List<Integer> selection = getSelectedItems();
mSelectedItems.clear();
for (Integer i : selection) {
notifyItemChanged(position);
}
}

可以看到作者也是通过在Adapter中维护一个选中的集合来实现Recyclerview的选中模式的,

总结

Recyclerview不仅在灵活度和扩展性上都较AbsListView好,在项目中也得到了大量的使用,也还有大量的未知方法等着去实践,
比如RecyclerviewScroll操作,RecycledViewPool.Recyclerview的上下拉刷新,
自定义LayoutManageritemDecorationitemAnimator等待

参考:
Android RecyclerView 使用完全解析 体验艺术般的控件
可拖拽的RecyclerView
Multi-Selection Mode for RecyclerView
Using the RecyclerView