谷歌在support v7中,加入了新的控件——RecyclerView,该控件整合了ListView、GridView的特点,而且最大的优点是可以很方便实现瀑布流效果,因此RecyclerView受到越来越多的开发者重视。所以,学习RecyclerView的使用也是很有必要的。
引入RecyclerView
由于该控件并不在Andorid SDK中的,而是在support v7包中,因此我们要手动添加该控件。
在build.gradle中添加如下依赖:
dependencies {
...
compile 'com.android.support:recyclerview-v7:23.1.1' }
几个重要的类
在认识RecyclerView的用法之前,我们要先认识几个它常用的内部类,因为这几个内部类很重要,贯穿整个使用过程:
1、RecyclerView.Adapter:抽象类,为RecyclerView提供数据,一般根据不同的业务需求来编写具体的实现类。
2、RecyclerView.LayoutManager:抽象类,主要用于测量RecyclerView的子Item,以及根据不同的布局方式来实现Item的布局效果,v 7包自带的实现类有:LinearLayoutManager、StaggeredGridLayoutManager、GridLayoutManager。
3、RecyclerView.ItemDecoration:抽象类,这个主要用于不同的Item之间添加分割线(可选)。官方没有实现类,所以如果要添加分割线,我们需要手动实现这个抽象类。
4、RecyclerView.ItemAnimator:抽象类,这个主要用于当一个item添加或者删除的时候出现的动画效果,官方提供一个默认的实现类。如果想要使我们的RecyclerView在添加、删除数据的时候有炫酷的动画,可以实现这个抽象类。
可以看到,这些重要的类都是抽象类,这就为RecyclerView的高度可定制性打下了坚实的基础,利用不同的实现类,能自由、灵活地使用RecyclerView,这也是RecyclerView的优秀之处。
开始上代码
一、recyclerView的布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.recyclerview.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>
二、MainActivity中的代码
public class MainActivity extends AppCompatActivity {
private Toolbar toolbar;
private RecyclerView mRecyclerView;
private RecyclerView.LayoutManager mLayoutManager;
private MyAdapter mAdapter;
private List<String> mData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initToolbar();
initData();
initRecyclerView();
}
private void initData() {
mData = new ArrayList<>();
for(int i=0;i<20;i++){
mData.add("Item "+i);
}
}
private void initRecyclerView() {
//1 实例化RecyclerView
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
mLayoutManager = new LinearLayoutManager(this);
//2 为RecyclerView创建布局管理器,这里使用的是LinearLayoutManager,表示里面的Item排列是线性排列
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new MyAdapter(mData);
//3 设置数据适配器
mRecyclerView.setAdapter(mAdapter);
}
三、最重要的适配器的Adapter的代码
与ListView类似地,RecyclerView也需要适配器来提供数据。上面说到RecyclerView提供了一个抽象类:RecyclerView.Adapter,我们通过继承该类来写自己的适配器。
public static abstract class Adapter<VH extends ViewHolder> {
public abstract VH onCreateViewHolder(ViewGroup parent, int viewType); // 1
public abstract void onBindViewHolder(VH holder, int position); // 2
public abstract int getItemCount(); // 3
}
继承该类的时候,必须重写这三个方法,我们分别解释一下这三个方法是什么作用:
①onCreateViewHolder:创建ViewHolder,该方法会在RecyclerView需要展示一个item的时候回调。重写该方法时,应该使ViewHolder加载item view的布局。这个能发避免了不必要的findViewById操作,提高了性能。如果熟悉ListView的ViewHolder操作那么也能很容易理解这个。
②onBindeViewHolder:该方法在RecyclerView在特定位置展示数据时候回调,顾名思义,把数据绑定、填充到相应的item view中。
③getItemCount:返回数据的数量。
我们注意到,继承该类的时候需要声明它的泛型类型VH,VH继承自RecyclerView.ViewHolder,同时第①个方法的返回值也是VH,由于ViewHolder是根据业务需求而变化的,不同的业务需求而需要的ViewHolder不尽相同,所以没必要单独写一个ViewHolder.java文件,因此我们可以在Adapter子类内部实现一个内部类ViewHolder,这样也符合单一职责原则。具体的Adapter适配器代码如下所示,MyAdapter.java:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private List<String> mDataSet;
//构造器,接受数据集
public MyAdapter(List<String> data){
mDataSet = data;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//加载布局文件
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.itemlayout,parent,false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
//将数据填充到具体的view中
holder.mTextView.setText(mDataSet.get(position));
}
@Override
public int getItemCount() {
return mDataSet.size();
}
class ViewHolder extends RecyclerView.ViewHolder{
public TextView mTextView;
public ViewHolder(View itemView) {
super(itemView);
//由于itemView是item的布局文件,我们需要的是里面的textView,因此利用itemView.findViewById获
//取里面的textView实例,后面通过onBindViewHolder方法能直接填充数据到每一个textView了
mTextView = (TextView) itemView.findViewById(R.id.num);
}
}
}
以上的代码的执行结果大概是这样