Android RecyclerView
1.基本介绍:
1.1 什么是RecyclerView
官方的说明:
RecyclerView is a more advanced and flexible version of ListView. This widget is a container for large sets of views that can be recycled and scrolled very efficiently. Use the RecyclerView widget when you have lists with elements that change dynamically.
简单说就是当你需要动态展示一组数据的时候就会需要用到它。
该控件用于在有限的窗口中展示大量数据集,其实这样功能的控件我们并不陌生,例如:ListView、GridView。
1.2 对比listview
用来替代ListView的使用,在RecyclerView标准化了ViewHolder类似于ListView中convertView用来做视图缓存.
先来说说RecyclerView的有点就是,他可以通过设置LayoutManager来快速实现listview、gridview、瀑布流的效果,而且还可以设置横向和纵向显示,添加动画效果也非常简单(自带了ItemAnimation,可以设置加载和移除时的动画,方便做出各种动态浏览的效果),也是官方推荐使用的.
对比listview 的好处。
那么有了ListView、GridView为什么还需要RecyclerView这样的控件呢?整体上看RecyclerView架构,提供了一种插拔式的体验,高度的解耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator实现令人瞠目的效果。
2 基本使用
2.1 第一个案例
2.1.1 Step1 导包
Step1 导入依赖包 在module的 build.gradle文件中增加recycleview 的依赖包
compile 'com.android.support:recyclerview-v7:23.4.0'
加入后如下
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
compile 'com.android.support:recyclerview-v7:23.4.0'
}
2.1.2 Step2声明控件及子view
在mainActivity的layou布局文件中增加recycleview控件
<android.support.v7.widget.RecyclerView
android:id="@+id/id_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
-增加recycleview中显示的每个子view的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:id="@+id/itemLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="220dp"
android:layout_height="220dp"
android:id="@+id/avatar_image"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:paddingLeft="10dp"
android:layout_height="wrap_content"
android:id="@+id/rank_text"/>
<TextView
android:layout_width="0dp"
android:layout_weight="2"
android:gravity="center"
android:layout_height="wrap_content"
android:id="@+id/name_text"/>
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:id="@+id/gender_text"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:paddingLeft="10dp"
android:layout_height="wrap_content"
android:id="@+id/nationality_text"/>
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:gravity="center"
android:layout_height="wrap_content"
android:id="@+id/work_text"/>
</LinearLayout>
</LinearLayout>
2.1.3 Step3在MainActivity里写代码
Step3:在MainActivity里写代码
1.准备数据recycleview里放的数据
声明成员变量
private List<Star> stars;
一个javaBean
package com.example.recyclerview.bean;
/**
* Created by CryRobot.
* rank,姓名,国籍 及 照片性别,作品
*/
public class Star {
private int rank;
private String name;
private String nationality;
private int avatar;
private String gender;
private String works;
public int getRank() {
return rank;
}
public void setRank(int rank) {
this.rank = rank;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNationality() {
return nationality;
}
public void setNationality(String nationality) {
this.nationality = nationality;
}
public int getAvatar() {
return avatar;
}
public void setAvatar(int avatar) {
this.avatar = avatar;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getWorks() {
return works;
}
public void setWorks(String works) {
this.works = works;
}
@Override
public String toString() {
return "Star{" +
"rank=" + rank +
", name='" + name + '\'' +
", nationality='" + nationality + '\'' +
", avatar='" + avatar + '\'' +
", gender='" + gender + '\'' +
", works='" + works + '\'' +
'}';
}
public Star(int rank, String name, String nationality, int avatar, String gender, String works) {
this.rank = rank;
this.name = name;
this.nationality = nationality;
this.avatar = avatar;
this.gender = gender;
this.works = works;
}
public Star() {
}
}
写一个initData初始化之
private void initData() {
stars = new ArrayList<Star>();
Star star1 = new Star(11,"周杰伦","中国",R.drawable.zhoujielun,"男","稻香");
Star star2 = new Star(12,"施瓦辛格","美国",R.drawable.shiwaxinge,"男","终结者");
Star star3 = new Star(13,"黛安娜","英国",R.drawable.daianna,"女","开罗紫玫瑰");
Star star4 = new Star(14,"李小龙","中国",R.drawable.lixiaolong,"男","精武门");
Star star5 = new Star(15,"史泰龙","中国",R.drawable.sitailong,"男","洛奇");
stars.add(star1);
stars.add(star2);
stars.add(star3);
stars.add(star4);
stars.add(star5);
}
在oncreate里调用initData (); 可以完成数据的初始化
2.实现recycleview的适配器:
适配器实现如下:
class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder>{
//创建保持view控件的holder
@Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//将
MyHolder myHolder = new MyHolder(View.inflate(MainActivity.this,R.layout.list_item,null));
return myHolder;
}
//设置每个view的显示内容
@Override
public void onBindViewHolder(MyHolder holder, int position) {
Star star = stars.get(position);
int rank = star.getRank();
String name = star.getName();
String nationality = star.getNationality();
int avatar = star.getAvatar();
String gender = star.getGender();
String works = star.getWorks();
ViewGroup.LayoutParams layoutParams = holder.avatar_image.getLayoutParams();
if(position%2==0){
layoutParams.height = 550;
}else{
layoutParams.height = 600;
}
holder.rank_text.setText(rank+"");
holder.avatar_image.setImageResource(avatar);
holder.name_text.setText(name);
holder.nationality_text.setText(nationality);
holder.gender_text.setText(gender);
holder.work_text.setText(works);
}
@Override
public int getItemCount() {
return stars.size();
}
//控件存放。findiew
class MyHolder extends RecyclerView.ViewHolder{
TextView rank_text ;
TextView name_text ;
TextView nationality_text;
TextView gender_text ;
TextView work_text ;
ImageView avatar_image;
LinearLayout itemLayout;
public MyHolder(View itemView) {
super(itemView);
rank_text = (TextView)itemView.findViewById(R.id.rank_text);
name_text = (TextView)itemView.findViewById(R.id.name_text);
nationality_text = (TextView)itemView.findViewById(R.id.nationality_text);
gender_text = (TextView)itemView.findViewById(R.id.gender_text);
work_text = (TextView)itemView.findViewById(R.id.work_text);
avatar_image = (ImageView)itemView.findViewById(R.id.avatar_image);
itemLayout = (LinearLayout) itemView.findViewById(R.id.itemLayout);
}
}
}
3.在oncreate里去设置recycleview的使用。
以上完成后,可以看到效果如下;
这样recycleview的初步使用就搞定了!
2.2 第一个案例解释
上面案例我们使用到了一个新的Adapter,它里面有一个内部类和几个callback,我们来解释一下。
首先看下Adapter里的内部类从命名就可以看到,这是一个viewholder的具体实现。
这跟我们之前讲的viewholder实现一样,就是用这个类去保存一个控件,我们复用的时候直接从这个holder里拿出来即可。接下来看adapter里的几个callback函数
onCreateViewHolder
在listview里,我们比较熟悉viewholder的概念。就是为了复用view而在recycleview里onCreateViewHolder就是为了复用view。
所以就不用自己去创建viewholder了,在需要创建viewholder的时候,这个api会自动调用,去创建viewholder。
onBinderViewHolder(holder,position)类似于listview里的getView(position),给你一个position,并给你一个可以复用的holder,那你只需要填充数据就行. 这里我们就根据传入的position到我们的数据集合里去找对应的position要显示什么数据,然后设置到这个viewholder里对应的view上即可。
getItemCount()
这个api类似之前的getCount()就是获取我这个recycleview里一共要显示多少个数据.
3 进阶使用
好了,上面通过使用其默认的LinearLayoutManager。
实现了类似ListView样子的Demo。
给recycleview设置LayoutManager这是一个抽象类,好在系统提供了3个实现类:
LinearLayoutManager 现行管理器,支持横向、纵向。
GridLayoutManager 网格布局管理器
StaggeredGridLayoutManager 瀑布就式布局管理器
上面我们已经初步体验了下LinearLayoutManager,
接下来看GridLayoutManager。
3.1更改样式
3.1.1GridLayoutManager
要更改LayoutManager为GridLayoutManager,只需要做如下修改即可
其中GridLayoutManager第二个参数的意思是:
The number of columns in the grid
即这个网格布局每一行有几列。
更换之后我们可以看到布局变成了这样。
每行变成了四列。这其实就是一个GridView。
3.1.2StaggeredGridLayoutManager
Staggered 意为 错列的,错开的;
要更改LayoutManager为StaggeredGridLayoutManager,只需要做如下修改即可
其中StaggeredGridLayoutManager
构造函数的两个参数的意义分别为:
第二个参数是当前的recycleview是水平延伸还是竖直延伸。
第一个参数spancount :
如果是水平方向延伸,它表示几行数据
如果是竖直方向延伸,表示由几列数据。
我们以竖直方向延伸,spancount=3为例,效果如下,可以在竖直方向拖动
而若以水平方向延伸,spancount=3为例,效果如下,可以在水平方向拖动
3.2 增加控件之间的间隔
RecycleView提供了如下的API让我们去设置item之间的间隔。
mRecyclerView.addItemDecoration(decoration);
这里需要传入一个ItemDecoration,这是个抽象类
recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.bottom = 8;
outRect.top = 8;
outRect.right=18;
outRect.left=18;
}
});
官方目前并没有提供默认的实现类(囧)。
自己去实现。
该类并没有抽象方法,我们要自己去重写它的getItemOffsets方法
这个方法的作用是让我们去设定每一个item上下左右的留白。
我们做如上面所示:
outRect为item的四周矩形
通过构造函数传入一个留白像素值,那么上下左右我们都留这么大距离
写完之后,可以给recycleView设置我们自己实现的ItemDecoration
效果如下:(设置前面的对比)
设置前(图片取的不好,勿怪)
设置后:
3.3 瀑布流效果的实现
3.3.1 什么是瀑布流效果?
3.3.2 如何实现?
思路分析
从之前的介绍可以发现,瀑布流效果实际上是StaggeredGridLayoutManager,然后每个填充的view高度不同即可。
根据上述思路,我们来实现。
StaggeredGridLayoutManager staggeredLay = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(staggeredLay);
先回顾下之前我们的Adapter里面,返回的view是怎么做的
现在需要返回控件高度不一样。因为目前我们是三列,竖直方向。我们可以做如下修改,增加红色框内代码,动态调整每个子view的高度:
ViewGroup.LayoutParams layoutParams = holder.avatar_image.getLayoutParams();
if(position%2==0){
layoutParams.height = 550;
}else{
layoutParams.height = 600;
}
完成之后效果如下:
上下拖动可以看到瀑布流效果已经实现
4更多
未完,待续。
[完整代码:]
package com.example.recyclerview;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.example.recyclerview.bean.Star;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private List<Star> stars;
private RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.rv);
//1.初始化数据
initDate();
//2.实现recycleview的适配器:
// recyclerView.setLayoutManager(new LinearLayoutManager(this));
// recyclerView.setLayoutManager(new GridLayoutManager(this,3));
StaggeredGridLayoutManager staggeredLay = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(staggeredLay);
MyAdapter myAdapter = new MyAdapter();
recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.bottom = 8;
outRect.top = 8;
outRect.right=18;
outRect.left=18;
}
});
recyclerView.setAdapter(myAdapter);
/* //这里不能为每个item设置点击事件
recyclerView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
}
});*/
}
private void initDate() {
stars = new ArrayList<Star>();
Star star1 = new Star(11,"周杰伦","中国",R.drawable.zhoujielun,"男","稻香");
Star star2 = new Star(12,"施瓦辛格","美国",R.drawable.shiwaxinge,"男","终结者");
Star star3 = new Star(13,"黛安娜","英国",R.drawable.daianna,"女","开罗紫玫瑰");
Star star4 = new Star(14,"李小龙","中国",R.drawable.lixiaolong,"男","精武门");
Star star5 = new Star(15,"史泰龙","中国",R.drawable.sitailong,"男","洛奇");
stars.add(star1);
stars.add(star2);
stars.add(star3);
stars.add(star4);
stars.add(star5);
}
class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder>{
//创建保持view控件的holder
@Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//将
MyHolder myHolder = new MyHolder(View.inflate(MainActivity.this,R.layout.list_item,null));
return myHolder;
}
//设置每个view的显示内容
@Override
public void onBindViewHolder(MyHolder holder, int position) {
Star star = stars.get(position);
int rank = star.getRank();
String name = star.getName();
String nationality = star.getNationality();
int avatar = star.getAvatar();
String gender = star.getGender();
String works = star.getWorks();
ViewGroup.LayoutParams layoutParams = holder.avatar_image.getLayoutParams();
if(position%2==0){
layoutParams.height = 550;
}else{
layoutParams.height = 600;
}
holder.rank_text.setText(rank+"");
holder.avatar_image.setImageResource(avatar);
holder.name_text.setText(name);
holder.nationality_text.setText(nationality);
holder.gender_text.setText(gender);
holder.work_text.setText(works);
}
@Override
public int getItemCount() {
return stars.size();
}
//控件存放。findiew
class MyHolder extends RecyclerView.ViewHolder{
TextView rank_text ;
TextView name_text ;
TextView nationality_text;
TextView gender_text ;
TextView work_text ;
ImageView avatar_image;
LinearLayout itemLayout;
public MyHolder(View itemView) {
super(itemView);
rank_text = (TextView)itemView.findViewById(R.id.rank_text);
name_text = (TextView)itemView.findViewById(R.id.name_text);
nationality_text = (TextView)itemView.findViewById(R.id.nationality_text);
gender_text = (TextView)itemView.findViewById(R.id.gender_text);
work_text = (TextView)itemView.findViewById(R.id.work_text);
avatar_image = (ImageView)itemView.findViewById(R.id.avatar_image);
itemLayout = (LinearLayout) itemView.findViewById(R.id.itemLayout);
}
}
}
}