前言
学习使用RecyclerView也有一段时间,一直都没有时间做个总结,就抽空想把RecyclerView的一些使用方法总结出来,方便大家也方便自己查阅。
简介
RecyclerView是support.v7包中的控件,可以说是ListView和GridView的增强升级版。既然官方已经提供了ListView和GridView,为什么还要提供RecyclerView呢?相对于来说RecyclerView肯定是比他们具有一些没有的优势。总的来说就是:低耦合高内聚,RecyclerView已经标准化ViewHolder,我们自定义的ViewHoler需要继承 RecyclerView.ViewHolder,然后在构造方法中初始化控件。通过设置不同的LayoutManager,可以实现Item不同的布局方式。插拔式的使用体验,结合ItemDecoration , ItemAnimator,ItemTouchHelper,则可以实现Item之间的分割线、动画,滑动拖拽等炫酷效果,这是ListView、GridView等控件难以企及的。
RecyclerView的简单使用
首先添加依赖库:
implementation 'com.android.support:recyclerview-v7:27.1.1'
activity的布局:
Item的布局:
在Activity中获取RecyclerView,并设置LayoutManager以及Adapter:
//初始化数据
List datas = new ArrayList<>();
for(int i=0;i<10;i++){
datas.add("item "+i);
}
recyclerView = findViewById(R.id.recycler_view);
//设置LayoutManager为LinearLayoutManager
recyclerView.setLayoutManager(new LinearLayoutManager(this));
//设置Adapter
recyclerView.setAdapter(new GeneralAdapter(this,datas));
这里的LayoutManager就是RecyclerView的布局管理器,用以实现Item不同布局排列方式,RecyclerView必须调用setLayoutManager设置布局管理器。RecyclerView中默认带有三个布局管理器:LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager,这三种布局管理器都支持横向和纵向排列以及反向滑动,这个在后面会讲解到。
Adapter的代码:
public class GeneralAdapter extends RecyclerView.Adapter {
//当前上下文对象
Context context;
//RecyclerView填充Item数据的List对象
List datas;
public GeneralAdapter(Context context,List datas){
this.context = context;
this.datas = datas;
}
//创建ViewHolder
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//实例化得到Item布局文件的View对象
View v = View.inflate(context, R.layout.item_recycler,null);
//返回MyViewHolder的对象
return new MyViewHolder(v);
}
//绑定数据
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
holder.textView.setText(datas.get(position));
}
//返回Item的数量
@Override
public int getItemCount() {
return datas.size();
}
//继承RecyclerView.ViewHolder抽象类的自定义ViewHolder
class MyViewHolder extends RecyclerView.ViewHolder{
TextView textView;
public MyViewHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.text);
}
}
}
这里的Adapter与ListView的Adapter相差不大,只不过这里是继承自RecyclerView.Adapter这个抽象类。后面是一个必须继承自RecyclerView.ViewHolder抽象类的ViewHolder的泛型约束,也就是GeneralAdapter.MyViewHolder这个内部类,这个在前言中讲到过。RecyclerView.Adapter抽象类有三个必须实现的抽象方法:
public abstract VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType);
public abstract void onBindViewHolder(@NonNull VH holder, int position);
public abstract int getItemCount();
具体的用途上方Adapter的代码中都有注释。
以上就是RecyclerView的简单使用了,献上效果图:
item的点击事件
在RecyclerView当中,并没有如同ListView那样并直接提供类似setOnItemClickListener( )和setOnItemLongClickListener ( )的方法。如果要实现Item的点击事件,我们可以自己去实现。
这里给出两种方法:
① 在Adapter里面直接对控件做点击事件
② 写接口,在Activity或Fragment上实现接口中定义的方法
方法一:
@Override
public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) {
holder.textView.setText(datas.get(position));
//直接对控件做点击事件
holder.textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(context,holder.textView.getText()+"被点击了",
Toast.LENGTH_SHORT).show();
}
});
}
方法二:
定义回调接口:
/**
* 设置回调接口
*/
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
/**
* 设置长按回调接口
*/
public interface OnItemLongClickListener {
boolean onItemLongClick(View view, int position);
}
Adapter中的部分代码:
public class GeneralAdapter extends RecyclerView.Adapter {
//当前上下文对象
Context context;
//RecyclerView填充Item数据的List对象
List datas;
public GeneralAdapter(Context context,List datas){
this.context = context;
this.datas = datas;
}
/**
* 事件回调监听
*/
private OnItemClickListener onItemClickListener;
private OnItemLongClickListener onItemLongClickListener;
/**
* 设置回调监听
*
* @param listener
*/
public void setOnItemClickListener(OnItemClickListener listener) {
this.onItemClickListener = listener;
}
public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) {
this.onItemLongClickListener = onItemLongClickListener;
}
。。。。。。。。。
//绑定数据
@Override
public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {
holder.textView.setText(datas.get(position));
//通过接口回调响应点击事件
holder.textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(onItemClickListener != null){
onItemClickListener.onItemClick(view,position);
}
}
});
//通过接口回调响应长按事件
holder.textView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
if(onItemLongClickListener != null){
return onItemLongClickListener.onItemLongClick(view,position);
}
return false;
}
});
}
。。。。。。。
}
Activity中使用:
//点击事件
adapter.setOnItemClickListener(new GeneralAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Toast.makeText(GeneralActivity.this,datas.get(position)+"被点击了",
Toast.LENGTH_SHORT).show();
}
});
//长按事件
adapter.setOnItemLongClickListener(new GeneralAdapter.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(View view, int position) {
Toast.makeText(GeneralActivity.this,datas.get(position)+"被长按了",
Toast.LENGTH_SHORT).show();
return true;
}
});
效果图:
布局管理器
前文说到RecyclerView的使用必须调用setLayoutManager来设置布局管理器,是为什么呢?因为RecyclerView不像ListView Item只有垂直排列一种排列方式,而RecyclerView通过setLayoutManager设置不同的布局管理器,Item就会按照设置的布局管理器的排列方式来排列。如果不调用setLayoutManager来设置布局管理器就会导致RecyclerView不知道它的Item如何布局,界面上就会一片空白。RecyclerView自身带有三种默认的布局管理器:LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager。
LinearLayoutManager线性布局管理器
LinearLayoutManager就如同它的翻译一样,线性布局管理器。设置这个布局管理器的话,可以设置它的排列方向,通过setOrientation()函数设置,参数可以是水平或者垂直。如果是垂直的话,那就跟ListView一模一样了。也就是前面简单使用中的例子。
LinearLayoutManager布局管理器默认使用垂直排列布局,而需要水平排列布局的话则可以通过LinearLayoutManager对象的setOrientation方法设置,此方法接收int类型的值,分别为RecyclerView中的两个Int常量:
public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
public static final int VERTICAL = LinearLayout.VERTICAL;
HORIZONTAL :代表水平排列
VERTICAL :代表垂直排列
也可以在new出LinearLayoutManager对象的时候调用它的三个参数的构造方法设置它的布局排列方向。
public LinearLayoutManager(Context context, @RecyclerView.Orientation int orientation,
boolean reverseLayout)
第二个参数就是这个布局管理器的排列方式,依旧是传入上方两个常量值中的其中一个。第三个参数一般传false,它的用途是当为true时数据和滑动都是反向的。具体意思可以自行实验。
在前面的代码基础上,放上水平排列的代码
Item布局:
Activity中的代码:
public class GeneralActivity extends AppCompatActivity {
RecyclerView recyclerView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_general);
//初始化数据
List datas = new ArrayList<>();
for(int i=0;i<10;i++){
datas.add("item "+i);
}
recyclerView = findViewById(R.id.recycler_view);
//通过setOrientation设置或者直接在构造方法中设置
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(RecyclerView.HORIZONTAL);
//设置LayoutManager为LinearLayoutManager
recyclerView.setLayoutManager(new LinearLayoutManager(this,RecyclerView.HORIZONTAL,false));
//recyclerView.setLayoutManager(linearLayoutManager);
//设置Adapter
recyclerView.setAdapter(new GeneralAdapter(this,datas));
}
}
Adapter中无变化,就不放上来筹字数了。
呈上效果图:
GridLayoutManager网格布局管理器
网格布局管理器,顾名思义Item已网格方式排列。跟线性布局管理器一样,也支持通过setOrientation()或者构造方法来设置Item的排列方向。
垂直排列:
//设置LayoutManager为GridLayoutManager
recyclerView.setLayoutManager(new GridLayoutManager(this,3));
这里使用了GridLayoutManager两个参数的构造方法,第二个参数Item有几行或者几列。之所以这么说,是因为当水平排列时,就是有几行。垂直排列时就是有几列。当不设置排列方式时,默认使用垂直排列。
垂直排列效果图:
水平排列:
GridLayoutManager gridLayoutManager = new GridLayoutManager(this,3);
gridLayoutManager.setOrientation(RecyclerView.HORIZONTAL);
//设置LayoutManager为GridLayoutManager
recyclerView.setLayoutManager(gridLayoutManager);
效果图:
StaggeredGridLayoutManager 瀑布流布局管理器
通过设置StaggeredGridLayoutManager则可以实现炫酷的瀑布流效果。它最常用的构造函数就一个,StaggeredGridLayoutManager(int spanCount, int orientation),spanCount代表每行或每列的Item个数,orientation代表列表的方向,竖直或者水平。
要实现瀑布流效果(仅讨论竖直方向的瀑布流样式),每一个Item的高度要有所差别,如果所有的item的高度相同,就和网格样式是一样的展示效果。示例中就实现两中不同高度的Item,一个高度为100dp,一个高度为200dp。
item1布局:
Item2布局:
Adapter的代码:
public class StaggeredApapter extends RecyclerView.Adapter {
//当前上下文对象
Context context;
//RecyclerView填充Item数据的List对象
List datas;
public StaggeredApapter(Context context,List datas){
this.context = context;
this.datas = datas;
}
@Override
public int getItemViewType(int position) {
if(position %2 == 0){
return 0;
}else{
return 2;
}
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v;
if(viewType == 0){
v = View.inflate(context,R.layout.item_recycler,null);
}else{
v = View.inflate(context,R.layout.item2_recycler,null);
}
return new MyViewHolder(v);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
holder.textView.setText(datas.get(position));
}
@Override
public int getItemCount() {
return datas.size();
}
class MyViewHolder extends RecyclerView.ViewHolder{
TextView textView;
public MyViewHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.text);
}
}
}
这里Adapter的代码相对于之前,多重写了一个public int getItemViewType(int position)一个方法,这个方法是根据当前Item的position返回当前Item的类型。这里就是实现瀑布流的关键。可以看到在onCreateViewHolder方法中,我们根据不同的ViewType,初始化了不同 Item布局。这样Item的位置不一样, 那么它的高度就可能不一样。
Activity中的代码:
public class StaggeredLayoutActivity extends AppCompatActivity {
RecyclerView recyclerView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_general);
//初始化数据
List datas = new ArrayList<>();
for(int i=0;i<20;i++){
datas.add("item "+i);
}
recyclerView = findViewById(R.id.recycler_view);
//设置LayoutManager为StaggeredGridLayoutManager
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2,RecyclerView.VERTICAL));
//设置Adapter
recyclerView.setAdapter(new StaggeredApapter(this,datas));
}
}
效果图:
未完待续。。。。。。
敬请期待下篇的高级操作,Item间隔线、Item滑动删除、Item拖拽、Item添加移除动画、滑动动画、添加Footer,Header、分组、上拉加载、下拉刷新等。