在Holo的年代,要说到最复杂的组件绝对要数ListView,基于其视图和数据的分离的设计,我们要使用它要费劲周折来写自己的适配器。如今,Google在新的V7支持包中开放了RecyclerView这个旨在替代ListView的全新组件,其功能和ListView大致相同,作为新一代的数据列表组件,其自由度更大,也就是我们可以通过代码来控制列表的各种行为,代价当然是更复杂的代码实现。不过这绝对不影响我们学习这个组件,毕竟它真的太受我们开发者喜爱了。关于RecyclerView更多介绍,请看CSDN上的这篇译文: RecycleView译文
我们今天要实现RecyclerView显示简单的列表,在此之前,要先讲解一下理论知识。
RecyclerView与ListView不同的是,RecyclerView不再负责Item的摆放等显示方面的功能。所有 和布局、绘制等方面的工作Google都其拆分成不同的类进行管理。所以开发者可以自定义各种各样满足定制需求的的功能类。
下面是一些和RecyclerView相关的非常重要的类列表。
类名 | 说明 |
RecyclerView.Adapter | 托管数据集合,为每个Item创建视图 |
RecyclerView.ViewHolder | 承载Item视图的子视图 |
RecyclerView.LayoutManager | 负责Item视图的布局 |
RecyclerView.ItemDecoration | 为每个Item视图添加子视图,在Demo中被用来绘制Divider |
RecyclerView.ItemAnimator | 负责添加、删除数据时的动画效果 |
或许对于刚接触RecyclerView的你来说会有点难理解,简单来说就是我们可以通过代码来设置、修改列表的各种状态和属性,以上的几个类是我们常用到的,不过不是必须的。对于一般的列表,有了适配器Adapter、视图加载器ViewHolder以及布局管理器LayoutManger就足够了。当然,要想实现更酷炫的效果,剩下的分割线管理器ItemDecoration和修改数据动画ItemAnimator(这个可以指定默认的效果,比较方便)必不可少。接下来就是你最期待的讲解Demo部分了。有一点要先说明,虽然RecyclerView是support-labrary的一部分,但是我们使用android studio时工程自动加载的support:appcompat-v7并没有包含RecyclerView,所以我们要在使用之前加入这个组件:
bulid.gradle:
compile 'com.android.support:appcompat-v7:23.3.0'
compile 'com.android.support:recyclerview-v7:23.3.0'
引用了组件,就可以在布局文件直接使用了,我们的这个历程布局比较直观,只加入一个RecyclerView:
main_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
跟ListView类似,接下来我们要定义列表的子布局:
item_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:src="@android:drawable/sym_def_app_icon"
android:layout_width="0sp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<LinearLayout
android:layout_width="0sp"
android:layout_height="wrap_content"
android:layout_weight="5"
android:orientation="vertical">
<TextView
android:id="@+id/name"
android:text="name"
android:textColor="@android:color/white"
android:background="@android:color/holo_blue_light"
android:layout_width="match_parent"
android:layout_height="0sp"
android:layout_weight="3"
android:textSize="20sp" />
<TextView
android:id="@+id/messgae"
android:text="message"
android:layout_width="match_parent"
android:layout_height="0sp"
android:layout_weight="1"/>
</LinearLayout>
</LinearLayout>
基本上布局部分的代码没有新的内容,这难不倒你,甚至到了设置RecyclerView的代码部分也没有多大问题,因为跟我们使用ListView基本类似,当然前提是仅仅要实现列表功能,并假设我们的适配器已经实现好(RecyclerView的一大特点是其提供了自己的适配器RecyclerView.Adapter,所以我们不用纠结于使用哪种类型的适配器),关于适配器的实现会放在本历程讲解的最后面。现在先来看看在主活动中的代码:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private RecyclerAdapter adapter;
private List<Message> list = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
recyclerView = (RecyclerView)findViewById(R.id.list);
recyclerView.setLayoutManager(new LinearLayoutManager(this)); //设置RecyclerLayout的显示方式,我们使用垂直布局
initData(); //加载数据
adapter = new RecyclerAdapter(list);
recyclerView.setAdapter(adapter); //加载适配器
}
private void initData() {
String message = "abcdefghijklmnopqrstuvwxyz";
for(int i = 0; i < 26; i ++) {
list.add(new Message(String.format("%c%c%c", 'A'+i,'A'+i,'A'+i), message));
}
}
public class Message {
public String name;
public String message;
public Message(String name, String message) {
this.name = name;
this.message = message;
}
}
}
假设RecyclerAdapter是已经实现好的RecyclerView.Adpater的集成类。其实步骤大致上跟ListView相同的,不过还是要解释下。首先定义了一个Message类用来表示列表数据,其中只有两个与列表对应的字段name和message,接下来在initData方法中初始化数据。最后我们看到onCreate里面,对于下面几行代码:
recyclerView.setLayoutManager(new LinearLayoutManager(this)); //设置RecyclerLayout的显示方式,我们使用垂直布局
initData(); //加载数据
adapter = new RecyclerAdapter(list);
recyclerView.setAdapter(adapter); //加载适配器
有必要解释下第一行,这个方法就是指定之前说明的重要的类的其中之一的RecyclerView.LayoutManager,基本上有四种种类型可以选择,垂直线性布局、横向线性布局、矩阵布局(GridLayoutManager)和流布局(StaggeredGridLayoutManager)。这里我们使用了垂直线性布局,因为对于LinearLayoutManager默认的效果是垂直,要想切换到横向的布局可以通过设置LinearLayoutManager的orientation属性完成:
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(layoutManager);
RecyclerAdpater是继承了RecyclerView.Adpater的类,接下来就让我们详细来讲解这个过程。首先上代码:
RecyclerAdapter.java
//这里的泛型类型是我们定义好的内部类RecyclerAdapter.ViewHolder
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
List<?> list; //数据集
public RecyclerAdapter(List<?> list) {
this.list = list;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//创建新View,被LayoutManager所调用
ViewHolder holder = new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false));
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
//将数据与界面进行绑定的操作
holder.name.setText(((MainActivity.Message)list.get(position)).name);
holder.message.setText(((MainActivity.Message)list.get(position)).message);
}
@Override
public int getItemCount() {
//获取数据的数量
return list.size();
}
//内部类,继承RecyclerView.ViewHolder,持有每个Item的的所有界面元素
class ViewHolder extends RecyclerView.ViewHolder {
TextView name;
TextView message;
public ViewHolder(View view) {
super(view);
name = (TextView)view.findViewById(R.id.name);
message = (TextView)view.findViewById(R.id.messgae);
}
}
}
我们应该从ViewHolder先入手,要注意,无论是RecyclerAdapter类实现时指定的泛型类型ViewHolder还是这里的内部类ViewHolder,都是我们的自己实现的继承自RecyclerView.ViewHolder的子类,就是上面的摆在最后的内部类。
其实要实现Adapter,需要重写三个方法:
方法名 | 说明 |
onCreateViewHolder | 加载视图到ViewHolder |
onBindViewHolder | 加载数据到ViewHolder |
getItemCount | 返回数据的数量 |
不知道你对RecyclerView有没有更加深入的了解,有没有觉得其实也不过如此,没错,其实用起来还是挺像ListView的,当然如果只实现列表效果的话。最后效果如下:
Demo源码下载地址:Demo8:Recyclerview1