Android06之RecyclerView详解
上一次我们讲解了ListView和GridView两种控件的用法,这一次我们讲解新的控件RecyclerView,这个控件可以说是前两个控件的集成版本,并且拥有更多的功能。下面我们进行详细的讲解。
RecyclerView能够灵活的实现大数据集的展现,视图的复用管理比ListView好,能够展示列表、网格、瀑布流等形式,且不同的ViewHolder能够实现item多元化的功能。
接下来我们主要讲解RecyclerView的几种用法,包括:①列表视图;②水平滚动;③网格视图;④瀑布流。
我们新建recyclerview包,里面新建的类如下图所示:
其中RecyclerViewActivity相当于一个总的类,里面的代码主要用于按钮的跳转,我们先展示与其对应的布局文件activity_recycler_view.xml的代码,如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn_linear"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="列表视图"/>
<Button
android:id="@+id/btn_hor"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="水平滚动"/>
<Button
android:id="@+id/btn_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="网格视图"/>
<Button
android:id="@+id/btn_pu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="瀑布流"/>
</LinearLayout>
RecyclerViewActivity的代码如下:
package com.autumn.recyclerview;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.autumn.R;
public class RecyclerViewActivity extends AppCompatActivity {
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler_view);
//用于列表视图按钮的页面跳转
Button btnLinear = findViewById(R.id.btn_linear);
btnLinear.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(RecyclerViewActivity.this,LinearRecyclerViewActivity.class);
startActivity(intent);
}
});
//用于水平滚动按钮的页面跳转
Button btnHor = findViewById(R.id.btn_hor);
btnHor.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(RecyclerViewActivity.this,HorRecyclerViewActivity.class);
startActivity(intent);
}
});
//用于网格视图按钮的页面跳转
Button btnGrid = findViewById(R.id.btn_grid);
btnGrid.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(RecyclerViewActivity.this,GridRecyclerViewActivity.class);
startActivity(intent);
}
});
//用于瀑布流按钮的页面跳转
Button btnPu = findViewById(R.id.btn_pu);
btnPu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(RecyclerViewActivity.this,PuRecyclerViewActivity.class);
startActivity(intent);
}
});
}
}
主界面截图如下:
接下来我们就要处理各个按钮的点击事件了,我们先处理列表视图按钮,我们新建LinearRecyclerViewActivity活动类,附带的activity_linear_recycler_view.xml文件如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>
这里我们只引入一个RecyclerView的控件,具体样式我们会另外新建xml文件的。我们在layout下新建两个xml文件,分别是layout_linear_item.xml和layout_linear_item2.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="wrap_content"
android:background="@color/colorWhite">
<!--- RecyclerView中具体单项item的布局 -->
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textColor="#000"
android:textSize="20sp"/>
</LinearLayout>
<?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="wrap_content"
android:gravity="center"
android:background="@color/colorWhite">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textColor="#000"
android:text="以梦为马"
android:textSize="20sp"/>
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"/>
</LinearLayout>
经过对比我们可以发现,第一个仅仅包含文本,第二个则包含文本和图片,与之前类似,我们需要创建适配器LinearAdapter,代码如下:
package com.autumn.recyclerview;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.autumn.R;
public class LinearAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private OnItemClickListener listener;
public LinearAdapter(Context context,OnItemClickListener listener){
this.context = context;
this.listener = listener;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
//返回的是RecyclerView单项item的布局
if(i == 0)
return new LinearViewHolder(LayoutInflater.from(context).inflate(R.layout.layout_linear_item,viewGroup,false));
else
return new LinearViewHolder2(LayoutInflater.from(context).inflate(R.layout.layout_linear_item2,viewGroup,false));
}
//给viewHolder中控件进行赋值
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, final int position) {
//不同的viewHolder呈现出来的效果
if(getItemViewType(position) == 0){
((LinearViewHolder)viewHolder).textView.setText("以梦为马,不负韶华");
}else{
((LinearViewHolder2)viewHolder).imageView.setImageResource(R.drawable.beauty_girl);
((LinearViewHolder2)viewHolder).textView.setText("面朝大海,春暖花开");
}
//设置点击监听事件
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onClick(position);
//Toast.makeText(context,"click..."+position,Toast.LENGTH_SHORT).show();
}
});
}
@Override
public int getItemCount() {
return 20;
}
public int getItemViewType(int pos) {
if(pos %2 == 0)
return 0;
else
return 1;
}
//自定义内部类LinearViewHolder
class LinearViewHolder extends RecyclerView.ViewHolder {
private TextView textView;
public LinearViewHolder(@NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.tv_title);
}
}
class LinearViewHolder2 extends RecyclerView.ViewHolder {
private TextView textView;
private ImageView imageView;
public LinearViewHolder2(@NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.tv_title);
imageView = itemView.findViewById(R.id.iv);
}
}
public interface OnItemClickListener {
void onClick(int pos);
}
}
RecyclerView中没有item监听事件,所以我们需要自定义接口,然后我们也定义了两个内部类ViewHolder,分别用于加载两个布局文件,这里我们用item的下标进行判断加载了哪一种布局,pos为偶数,则加载第一种布局;pos为奇数,则加载第二种布局。其中onBindViewHolder方法主要用于给控件进行赋值,getItemCount方法用于返回Item的数量,这里我们设置为常量20。
LinearRecyclerViewActivity则主要用于设置布局样式,设置适配器以及添加分隔线。代码如下:
package com.autumn.recyclerview;
import android.graphics.Rect;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Toast;
import com.autumn.R;
public class LinearRecyclerViewActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_linear_recycler_view);
RecyclerView recyclerView = findViewById(R.id.rv_main);
recyclerView.setLayoutManager(new LinearLayoutManager(LinearRecyclerViewActivity.this));
recyclerView.addItemDecoration(new MyDecoration());
//设置适配器Adapter,其中监听事件方法需要自己定义
recyclerView.setAdapter(new LinearAdapter(LinearRecyclerViewActivity.this, new LinearAdapter.OnItemClickListener() {
@Override
public void onClick(int pos) {
Toast.makeText(LinearRecyclerViewActivity.this,"click..."+pos,Toast.LENGTH_SHORT).show();
}
}));
}
//定义内部类MyDecoration,并设置分隔线
class MyDecoration extends RecyclerView.ItemDecoration {
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(0,0,0,getResources().getDimensionPixelOffset(R.dimen.dividerHeight));
}
}
}
这里我们定义了内部类MyDecoration,主要用于item之间的分隔线,我们在values文件夹下新建dimens.xml文件,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="dividerHeight">4dp</dimen>
</resources>
到这儿一步列表视图就好了,运行截图如下:
我们添加了点击事件,默认下标从0开始。
接下来到了水平滚动了,我们新建HorRecyclerViewActivity活动类,附带的activity_hor_recycler_view.xml布局文件代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_hor"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
这里我们和上面一样,只加入了一个RecyclerView的控件。具体的样式布局在layout_hor_item.xml文件中,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorWhite"
android:paddingLeft="10dp"
android:paddingRight="10dp">
<!--- RecyclerView中具体单项item的布局 -->
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textColor="#000"
android:text="Hello"
android:textSize="20sp"/>
</LinearLayout>
然后操作和上面差不多,我们新建适配器HorAdapter,代码如下:
package com.autumn.recyclerview;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import com.autumn.R;
public class HorAdapter extends RecyclerView.Adapter<HorAdapter.LinearViewHolder> {
private Context context;
private OnItemClickListener clickListener;
public HorAdapter(Context context,OnItemClickListener listener){
this.context = context;
this.clickListener = listener;
}
@NonNull
@Override
public HorAdapter.LinearViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
//返回的是RecyclerView单项item的布局
return new LinearViewHolder(LayoutInflater.from(context).inflate(R.layout.layout_hor_item,viewGroup,false));
}
//给viewHolder中控件textView进行赋值
@Override
public void onBindViewHolder(@NonNull HorAdapter.LinearViewHolder viewHolder, final int position) {
viewHolder.textView.setText("lsq");
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
clickListener.OnClick(position);
//Toast.makeText(context,"click..."+position,Toast.LENGTH_SHORT).show();
}
});
}
@Override
public int getItemCount() {
return 20;
}
//自定义内部类LinearViewHolder
class LinearViewHolder extends RecyclerView.ViewHolder {
private TextView textView;
public LinearViewHolder(@NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.tv_title);
}
}
public interface OnItemClickListener {
void OnClick(int pos);
}
}
具体解释就不多说了,和前面一个差不多。接下来就是完善HorReyclerViewActivity的代码了,如下所示:
package com.autumn.recyclerview;
import android.graphics.Rect;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Toast;
import com.autumn.R;
public class HorRecyclerViewActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hor_recycler_view);
RecyclerView RvHor = findViewById(R.id.rv_hor);
LinearLayoutManager manager = new LinearLayoutManager(HorRecyclerViewActivity.this);
manager.setOrientation(LinearLayoutManager.HORIZONTAL);
RvHor.setLayoutManager(manager);
RvHor.addItemDecoration(new MyDecoration());
RvHor.setAdapter(new HorAdapter(HorRecyclerViewActivity.this, new HorAdapter.OnItemClickListener() {
@Override
public void OnClick(int pos) {
Toast.makeText(HorRecyclerViewActivity.this,"click..."+pos,Toast.LENGTH_SHORT).show();
}
}));
}
//内部装饰类(用于加上分隔线)
class MyDecoration extends RecyclerView.ItemDecoration {
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(0,0,getResources().getDimensionPixelOffset(R.dimen.dividerHeight),0);
}
}
}
这里我们添加了水平的分割线,并添加了点击事件,运行截图如下所示:
接下来就到了网格视图了,同理,新建GridRecyclerViewActivity,同时新建activity_grid_recycler_view.xml,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
具体的布局文件为layout_grid_recycler_view.xml,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorWhite"
android:paddingLeft="10dp"
android:paddingRight="10dp">
<!--- RecyclerView中具体单项item的布局 -->
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textColor="#000"
android:text="Hello"
android:textSize="20sp"/>
</LinearLayout>
我们仅仅添加了一个TextView控件,用于简单的测试,接下来我们新建GridAdapter适配器,代码如下:
package com.autumn.recyclerview;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.autumn.R;
public class GridAdapter extends RecyclerView.Adapter<GridAdapter.LinearViewHolder> {
private Context context;
private OnItemClickListener clickListener;
public GridAdapter(Context context, OnItemClickListener listener){
this.context = context;
this.clickListener = listener;
}
@NonNull
@Override
public GridAdapter.LinearViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
//返回的是GridRecyclerView单项item的布局
return new LinearViewHolder(LayoutInflater.from(context).inflate(R.layout.layout_grid_recycler_item,viewGroup,false));
}
//给viewHolder中控件textView进行赋值
@Override
public void onBindViewHolder(@NonNull GridAdapter.LinearViewHolder viewHolder, final int position) {
viewHolder.textView.setText("Hello");
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
clickListener.OnClick(position);
//Toast.makeText(context,"click..."+position,Toast.LENGTH_SHORT).show();
}
});
}
@Override
public int getItemCount() {
return 60;
}
//自定义内部类LinearViewHolder
class LinearViewHolder extends RecyclerView.ViewHolder {
private TextView textView;
public LinearViewHolder(@NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.tv_title);
}
}
public interface OnItemClickListener {
void OnClick(int pos);
}
}
适配器写好之后,接下来就到了GridRecyclerViewActivty了,代码如下:
package com.autumn.recyclerview;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.Toast;
import com.autumn.R;
public class GridRecyclerViewActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_grid_recycler_view);
RecyclerView RvGrid = findViewById(R.id.rv_grid);
//一行展示3个Item
RvGrid.setLayoutManager(new GridLayoutManager(GridRecyclerViewActivity.this,3));
RvGrid.setAdapter(new GridAdapter(GridRecyclerViewActivity.this, new GridAdapter.OnItemClickListener() {
@Override
public void OnClick(int pos) {
Toast.makeText(GridRecyclerViewActivity.this,"click..."+pos,Toast.LENGTH_SHORT).show();
}
}));
}
}
运行的效果如下图所示:
同样的,我们在GridLayoutManager中设置一行显示3个Item,并添加了监听事件。
接下来我们介绍最后一个版块,即瀑布流的布局。
我们新建PuRecyclerViewActivity,然后在layout下新建activity_pu_recycler_view.xml文件,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_pu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorGrayDark">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
具体的布局样式我们重新定义,新建layout_staggered_grid_recycler_view.xml文件,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorWhite">
<!--- RecyclerView中具体单项item的布局 -->
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"/>
</LinearLayout>
然后是创建适配器StaggeredGridAdapter,具体代码如下:
package com.autumn.recyclerview;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.autumn.R;
public class StaggeredGridAdapter extends RecyclerView.Adapter<StaggeredGridAdapter.LinearViewHolder> {
private Context context;
private OnItemClickListener clickListener;
public StaggeredGridAdapter(Context context, OnItemClickListener listener){
this.context = context;
this.clickListener = listener;
}
@NonNull
@Override
public StaggeredGridAdapter.LinearViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
//返回的是GridRecyclerView单项item的布局
return new LinearViewHolder(LayoutInflater.from(context).inflate(R.layout.layout_staggered_grid_recycler_item,viewGroup,false));
}
//给viewHolder中控件textView进行赋值
@Override
public void onBindViewHolder(@NonNull StaggeredGridAdapter.LinearViewHolder viewHolder, final int position) {
if(position % 2 != 0){
viewHolder.imageView.setImageResource(R.drawable.image1);
}else {
viewHolder.imageView.setImageResource(R.drawable.image2);
}
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
clickListener.OnClick(position);
//Toast.makeText(context,"click..."+position,Toast.LENGTH_SHORT).show();
}
});
}
@Override
public int getItemCount() {
return 30;
}
//自定义内部类LinearViewHolder
class LinearViewHolder extends RecyclerView.ViewHolder {
private ImageView imageView;
public LinearViewHolder(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.iv);
}
}
public interface OnItemClickListener {
void OnClick(int pos);
}
}
这里的和第一个LinearAdapter差不多,position为奇数加载图片1,为偶数加载图片2,我们这里挑了两张图片的长宽相差很大,以此显示出交错感,然后PuRecyclerViewActivity的代码如下:
package com.autumn.recyclerview;
import android.graphics.Rect;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;
import android.widget.Toast;
import com.autumn.R;
public class PuRecyclerViewActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pu_recycler_view);
RecyclerView RvPu = findViewById(R.id.rv_pu);
//垂直有两列
RvPu.setLayoutManager(new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL));
RvPu.addItemDecoration(new MyDecoration());
RvPu.setAdapter(new StaggeredGridAdapter(PuRecyclerViewActivity.this, new StaggeredGridAdapter.OnItemClickListener() {
@Override
public void OnClick(int pos) {
Toast.makeText(PuRecyclerViewActivity.this,"click:"+pos,Toast.LENGTH_SHORT).show();
}
}));
}
//内部类,用于创建分割线
class MyDecoration extends RecyclerView.ItemDecoration {
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
int gap = getResources().getDimensionPixelSize(R.dimen.dividerHeight);
outRect.set(gap,gap,gap,gap);
}
}
}
运行截图如下所示:
好了,有关RecyclerView的讲解就到这里了,全部的代码(包括之前的)我已经上传到GitHub上,链接为https://github.com/229394/AndroidBasic,欢迎大家Star!