在这里总结一下RecylerView的使用
注:这里主要是讲的如何去使用它,而没有很深度的去解析各种方法是怎样的,更没有去解析源码之类的。
方便以后复习查询
也加固自己的知识
这里先介绍一下RecylerView,这个是一个强大的滚动控件,可以代替之前的ListView,做很多ListView做不到的工作,比如横向的滚动等等,有更美的更强大的效果和体验。
- RecyclerView的基本用法_线性布局(横向与纵向)
首先RecyclerView作为一个新增的控件,为了让RecyclerView在所有的Android版本上都能使用,RecyclerView被定义在support库当中。所以在使用之前得添加相应的依赖库到项目中:
打开build.gradle(Module:app)文件:
dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support.constraint:constraint-layout:1.0.2' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.1' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' implementation 'com.android.support:recyclerview-v7:26.1.0' }
Android Studio 3.0 以后添加依赖不再是compile 而是implementation。注意,因为之前说了,这个依赖库是support库里面的,所以版本号要同你项目中的support库一致,也就是最后一行的版本号,要和第二行的版本号一致,否则要报错。写好依赖之后,再Sync Now一下(同步)。就可以使用Recycler View了。
添加依赖之后就可以在布局里面添加控件了:
<android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent"/>
和listview一样,需要创建adapter来放数据。
所以我们新建一个类来继承RecyclerView.Adapter
public class BaseAdapter extends RecyclerView.Adapter<BaseAdapter.ViewHolder> { }
因为我们是要用自己定义的viewholder,所以在填泛型的时候就填我们自定义的,然后在红线(我复制的代码看不到红线,实际打完这段代码,在这个代码下面就会出现红线),这个时候需要导入方法和新建内部类,但是都不要怕,我们直接把鼠标移动到最后那个ViewHolder上面,然后按住alt+回车,系统就会让我们选择是否创建内部类,我们只要选择Create class 'ViewHolder'就可以了。
public class BaseAdapter extends RecyclerView.Adapter<BaseAdapter.ViewHolder> { public class ViewHolder { } }
这样工具就帮我们创建好了,内部类,也就是我们自定义的viewholder(如果不知道viewholder是干嘛的,可以去学习一下listview,viewholder这个是用来缓存列表子view的)。内部类创建好了。但是红线还在,是我们继承了RecyclerView.Adapter但是还需要实现这个类的一些方法,也很简单,只需要把鼠标移动到红线上面然后alt+回车,然后选择Implement methods,就会弹出一个方框,让我们选择要实现的一些父类的方法,这里全选就可以了,都是必须要实现的。
最后你会发现,BaseAdapter.ViewHolder下面还有红线,是因为我们创建的内部类还需要继承RecyclerView.Holder,不然系统就不会认为我们创建的这个内部类是一个holder,所以也很简单,鼠标移动到红线上面,然后alt+回车,Make 'ViewHolder' extend 'android.support7.widget.RecyclerView.ViewHolder'
继承之后需要实现父类的方法,同理:
public class BaseAdapter extends RecyclerView.Adapter<BaseAdapter.ViewHolder> { @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return null; } @Override public void onBindViewHolder(ViewHolder holder, int position) { } @Override public int getItemCount() { return 0; } public class ViewHolder extends RecyclerView.ViewHolder { public ViewHolder(View itemView) { super(itemView); } } }
这样我们的一个adapter就创建好了,虽然代码有点多,感觉也很难记有这么多方法,但是实际上我们只需要打出第一行,其余的代码利用工具就可以帮我们完成,非常的方便。所以也非常的简单,之后我就不在这么详细的说去怎么操作了。我就直接说继承哪个类和实现父类的方法,就行了,不在累述如何去通过工具来做了。这篇文章建立在listview学习的基础之上,下面我就不再多解释什么是item,和怎么导入布局,为啥传入数据了。
现在adapter有了,其实可以看到和listview的adapter是很相似的,接下来是创建我们的item布局,就简单的放一张图片和文字吧
<?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="wrap_content" android:orientation="horizontal"> <ImageView android:id="@+id/iv_bi" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center"/> <TextView android:id="@+id/tv_bi" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> </LinearLayout>
然后在adapter中导入item布局,创建holder:
@Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.base_item,parent,false); ViewHolder holder = new ViewHolder(view); return holder; }
这里就和listview创建holder的方式不一样了,虽然方式不一样,但是作用是一样的,holder还是你所知道的那个holder。
对了,holder里面还得添加控件,和listview一样:
static class ViewHolder extends RecyclerView.ViewHolder { ImageView baseImageView; TextView baseTextView; ViewHolder(View itemView) { super(itemView); baseImageView = itemView.findViewById(R.id.iv_bi); baseTextView = itemView.findViewById(R.id.tv_bi); } }
这里我也很好奇,如果你不是新手,你肯定会问,怎么没用强转呢?我也很好奇,我的是3.0的编译器,可能谷歌已经给我们优化了这个问题。(这里留个坑,好奇的小伙伴可以去查一下)
然后创建我们的实体:
public class BaseEntity { private int baseImage; private String baseText; public int getBaseImage() { return baseImage; } public void setBaseImage(int baseImage) { this.baseImage = baseImage; } public String getBaseText() { return baseText; } public void setBaseText(String baseText) { this.baseText = baseText; } }
在adapter里面提供导入我们想要展示的数据的方法:
private List<BaseEntity> baseEntityList; public BaseAdapter(List<BaseEntity> baseEntityList) { this.baseEntityList = baseEntityList; }
和listview的adapter一样,我们在构建adapter的时候就可以把要展示的数据传进去。然后还需要小小的修改一下我们的adapter,我直接给出代码:
public class BaseAdapter extends RecyclerView.Adapter<BaseAdapter.ViewHolder> { private List<BaseEntity> baseEntityList; public BaseAdapter(List<BaseEntity> baseEntityList) { this.baseEntityList = baseEntityList; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.base_item,parent,false); ViewHolder holder = new ViewHolder(view); return holder; } @Override public void onBindViewHolder(ViewHolder holder, int position) { BaseEntity baseEntity = baseEntityList.get(position); holder.baseImageView.setImageResource(baseEntity.getBaseImage()); holder.baseTextView.setText(baseEntity.getBaseText()); } @Override public int getItemCount() { return baseEntityList.size(); } static class ViewHolder extends RecyclerView.ViewHolder { ImageView baseImageView; TextView baseTextView; ViewHolder(View itemView) { super(itemView); baseImageView = itemView.findViewById(R.id.iv_bi); baseTextView = itemView.findViewById(R.id.tv_bi); } }
然后就是使用了:
private void initView() { mRecyclerView = findViewById(R.id.recycler_view); initDatas();//初始化BaseEntityList LinearLayoutManager layoutManager = new LinearLayoutManager(this); mRecyclerView.setLayoutManager(layoutManager); BaseAdapter baseAdapter = new BaseAdapter(baseEntityList); mRecyclerView.setAdapter(baseAdapter); } private void initDatas() { baseEntityList = new ArrayList<>(); BaseEntity baseEntity; for (int i = 0;i<10;i++){ baseEntity = new BaseEntity(R.mipmap.red_heart,i+""); baseEntityList.add(baseEntity); } }
效果如下:
在使用方面和listview不一样的是,多添加了一个layoutManager(这个布局管理作用非常大,之后的实现横向滚动就靠它)
横向滚动:
LinearLayoutManager layoutManager = new LinearLayoutManager(this); layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); mRecyclerView.setLayoutManager(layoutManager); BaseAdapter baseAdapter = new BaseAdapter(baseEntityList); mRecyclerView.setAdapter(baseAdapter);
只需要加这么一句代码就搞定了,非常的方便。当然item布局要改为横向的,效果如下:
- RecylcerView用法_网格布局:
RecyclerView.LayoutManager是一个抽象类,而LinearLayoutManager(线性布局管理器)是一个实现类,一共有三个实现类。
除了线性布局管理器以外还有以下两个实现类:
GridLayoutManager 网格布局管理器
StaggeredGridLayoutManager 瀑布流式布局管理器
接下来,我们就使用以下网格布局管理器
和我们之前使用线性布局管理器一样的用法,代码如下:
// LinearLayoutManager layoutManager = new LinearLayoutManager(this); // layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); GridLayoutManager layoutManager = new GridLayoutManager(this,3); //新建一个网格布局管理器 后面的参数 第一个是context 第二个是网格有几列 mRecyclerView.setLayoutManager(layoutManager); BaseAdapter baseAdapter = new BaseAdapter(baseEntityList); mRecyclerView.setAdapter(baseAdapter);
只需要改动一行代码就完成了,下面是效果截图:
网格布局和线性布局都非常的简单。
- RecylcerView用法_瀑布流布局:
首先先修改以下item布局里面的代码:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:orientation="vertical" android:background="@color/background"> <ImageView android:id="@+id/iv_bi" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal"/> <TextView android:id="@+id/tv_bi" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
这里添加了背景颜色和间距(5dp),方便等会儿我们更直观的看出效果
使用的代码部分:
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL); //第一个参数是列数 第二个参数是方向
也是只需要短短的一句就可以了,但是如果你这样运行的话,肯定是看不出效果的,为什么呢,因为你的每一个item数据都是一样的,所以显示不出效果,所以接下来稍微改变一下一些item的长度就可以了,代码如下:
private void initDatas() { baseEntityList = new ArrayList<>(); BaseEntity baseEntity; for (int i = 0;i<30;i++){ baseEntity = new BaseEntity(R.mipmap.red_heart,i+getRandomLengthName("_hello_world")); baseEntityList.add(baseEntity); } } private String getRandomLengthName(String name){ Random random = new Random(); int length = random.nextInt(20) + 1; StringBuilder builder = new StringBuilder(); for (int i = 0 ;i<length;i++){ builder.append(name); } return builder.toString(); }
本来文字部分只有 i ,但是我在i的后面加了随机个数的“_hello_world”,这样就保证了每个item 的长度都不一样了,然后我们运行一下看一下效果:
这样效果就出来了。 - RecyclerView点击事件的添加:
各种效果都是有了,但是如果不能互动是不是总感觉缺少了什么,接下来我们加上点击事件,这样就比较舒服了。
接下来我们改动一下adapter,我直接上代码:
public class BaseAdapter extends RecyclerView.Adapter<BaseAdapter.ViewHolder> { private List<BaseEntity> baseEntityList; public BaseAdapter(List<BaseEntity> baseEntityList) { this.baseEntityList = baseEntityList; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.base_item,parent,false); final ViewHolder holder = new ViewHolder(view); holder.baseView.setOnClickListener(new View.OnClickListener(){//给item添加监听 @Override public void onClick(View view) { int position = holder.getAdapterPosition(); Toast.makeText(view.getContext(), "你点击了 "+position, Toast.LENGTH_SHORT).show(); } }); holder.baseImageView.setOnClickListener(new View.OnClickListener() {//给item里面的图片添加监听 @Override public void onClick(View view) { int position = holder.getAdapterPosition(); Toast.makeText(view.getContext(), "你点击了 "+position+" 的图片", Toast.LENGTH_SHORT).show(); } }); return holder; } @Override public void onBindViewHolder(ViewHolder holder, int position) { BaseEntity baseEntity = baseEntityList.get(position); holder.baseImageView.setImageResource(baseEntity.getBaseImage()); holder.baseTextView.setText(baseEntity.getBaseText()); } @Override public int getItemCount() { return baseEntityList.size(); } static class ViewHolder extends RecyclerView.ViewHolder { View baseView; ImageView baseImageView; TextView baseTextView; ViewHolder(View itemView) { super(itemView); baseView = itemView; baseImageView = itemView.findViewById(R.id.iv_bi); baseTextView = itemView.findViewById(R.id.tv_bi); } } }
红色的字体就是改动的地方,先看ViewHolder这儿,给ViewHolder这儿多添加了一个View,然后给View赋值就是当前的itemView,目的是为了给整个item添加监听。
然后再看onCreateViewHolder这个方法这儿,这里是添加监听的地方,你看了这个地方之后就知道为什么要在holder里面多加一个view了。
而且你可以给item布局里面的所有控件添加监听,非常的方便,也非常的人性化。下面我们看下效果:
RecyclerView的基本用法就到这儿了,完成一般的任务是没有问题了,之后我会继续更新更多的更高级的用法。
第一次发博客,主要是用的自己的口吻来描述自己学到的东西。
如果有什么看不懂的方面欢迎大家留言。
这里基本上就讲了一下用法,关于更深层的各种谈论我这里就不能顾及到了。大家有兴趣可以去看看一些大牛写的文章。
文中部分代码引用于《第一行代码》郭霖
这里我给出项目的git克隆地址:https://gitee.com/MrWmago/RecyclerViewSummary.git