目录
本篇文章主要讲解滚动控件RecyclerView的使用,包括基本使用和点击事件。
序言
上篇文章主要讲解了ListView的用法,但是ListView并不是完全没有缺点的,如:不使用技巧优化,性能会很差;还有,扩展性也不够好,它只能实现数据纵向滚动的效果。
扫描二维码关注公众号,回复: 14696372 查看本文章为此RecyclerView不仅可以轻松实现和ListView同样的效果,还优化了ListView中存在的各种不足,且Android官方也更加推荐使用RecyclerView。
一、RecyclerView的基本用法
RecyclerView属于新增控件,被定义在了support库中,想要使用,需要在项目的build.gradle中添加相应的依赖库。
首先新建RecyclerView项目,并创建好活动。
打开app/build.gradle,在dependencies闭包中添加如下代码:
implementation 'androidx.recyclerview:recyclerview:1.2.1'
添加完后点击Sync Now来同步。
然后修改activity_main.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">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
接下来实现与前一文章的ListView相同的效果,直接将Image类、item.xml、image3.png复制过来(如有需要参考代码,请参考上一文章,链接:https://blog.csdn.net/Tir_zhang/article/details/129718771?spm=1001.2014.3001.5501)。
接下来为RecyclerView准备一个适配器,新建一个adapter类,代码如下:
代码稍微有点长,但是比ListView适配器更好理解。
首先定义一个内部类ViewHolder,继承自RecyclerView.ViewHolder,然后在构造函数中传入View参数,这个参数通常是RecyclerView子项的最外层布局,然后可以通过findViewById()方法来获取到布局中的ImageView和TextView实例了。
adapter的构造函数,用于把展示的数据源传进来。
adapter继承自RecyclerView.Adapter,需要重写onCreateViewHolder()、onBindViewHolder()、getItemCount()这3个方法。onCreateViewHolder()方法是用于创建ViewHolder实例的;onBindViewHolder()方法用于对RecyclerView子项数据赋值,会在子项被滚动到屏幕内的时候执行,通过position参数获取到当前项的实例,再设置到ImageView和TextView当中;getItemCount()方法用于告诉RecyclerView一共有多少子项,直接返回长度。
public class adapter extends RecyclerView.Adapter<adapter.ViewHolder> {
private List<Image> list;
static class ViewHolder extends RecyclerView.ViewHolder{
ImageView image;
TextView name;
public ViewHolder(View view){
super(view);
image = (ImageView) view.findViewById(R.id.image);
name = (TextView) view.findViewById(R.id.name);
}
}
public adapter(List<Image> list2){
list = list2;
}
public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType){
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,parent,false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
public void onBindViewHolder(ViewHolder holder,int position){
Image image = list.get(position);
holder.image.setImageResource(image.getImageId());
holder.name.setText(image.getName());
}
public int getItemCount(){
return list.size();
}
}
准备好适配器,可以使用RecyclerView了,修改MainActivity中的代码,如下:
下面的LayoutManager用于指定RecyclerView的布局方式,这里使用的LinearLayoutManager是线性布局的意思。
public class MainActivity extends AppCompatActivity {
private List<Image> list = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();//初始化数据
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
adapter ad = new adapter(list);
recyclerView.setAdapter(ad);
}
private void init(){
for(int i = 0; i < 2; i++){
Image a = new Image("A",R.drawable.image3);
list.add(a);
Image b = new Image("B",R.drawable.image3);
list.add(b);
Image c = new Image("C",R.drawable.image3);
list.add(c);
Image d = new Image("D",R.drawable.image3);
list.add(d);
Image e = new Image("E",R.drawable.image3);
list.add(e);
}
}
}
效果如下:
二、实现横向滚动和瀑布流布局
1、横向滚动
首先修改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="100dp"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"/>
</LinearLayout>
接下来修改MainActivity代码,如下:
只加入了一行代码: layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
默认是纵向排列,调用setOrientation()方法来设置布局排列方向。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();//初始化数据
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(layoutManager);
adapter ad = new adapter(list);
recyclerView.setAdapter(ad);
}
效果如下:
2、瀑布流布局
除LinearLayoutManager之外,还有GridLayoutManager和StaggeredGridLayoutManager这两种内置的布局方式。GridLayoutManager用来实现网格布局,StaggeredGridLayoutManager用来实现瀑布流布局,下面实现瀑布流布局。
修改item.xml代码,如下:
这里只修改了两部分,首先将LinearLayout的宽度由100dp改成了match_parent,因为瀑布流的宽度应该是根据布局的列数自动适配,而不是固定值;另外,TextView的对齐方式改成了左对齐。
<?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:layout_margin="5dp">
<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginTop="10dp"/>
</LinearLayout>
接着修改MainActivity.java代码,如下:
首先,再onCreate方法中,创建StaggeredGridLayoutManager实例,构造函数接收两个参数,第一个参数用于指定布局的列数,第二个参数用于指定布局的排列方向。
public class MainActivity extends AppCompatActivity {
private List<Image> list = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();//初始化数据
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
adapter ad = new adapter(list);
recyclerView.setAdapter(ad);
}
private void init(){
for(int i = 0; i < 5; i++){
Image a = new Image("AAAAAAAAAAAAAAAAAA",R.drawable.image3);
list.add(a);
Image b = new Image("BBBBBB",R.drawable.image3);
list.add(b);
Image c = new Image("CCCCCCCCCCC",R.drawable.image3);
list.add(c);
Image d = new Image("DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD",R.drawable.image3);
list.add(d);
Image e = new Image("EEE",R.drawable.image3);
list.add(e);
}
}
}
效果如下:
二、RecyclerView的点击事件
RecyclerView的点击事件需要我们自己给子项具体的View去注册点击事件,比ListView实现要复杂一点。
那么为什么RecyclerView设计的更复杂一点?假设以下场景:如果想要点击子项里具体的按钮,如何做?ListView的setOnItemClickListener()方法注册的是子项的点击事件,实现这个功能比较麻烦,为此,RecyclerView直接去除了子项点击事件的监听器,所有的点击事件都有具体的View去注册。
接下来尝试实现。
修改adapter中的代码,如下:
下面加粗部分为新增代码。
imageView变量用来保存子项最外层布局的实例,然后在onCreateViewHolder()方法中注册点击事件,这里为ImageView注册了点击事件。
public class adapter extends RecyclerView.Adapter<adapter.ViewHolder> { private List<Image> list; static class ViewHolder extends RecyclerView.ViewHolder{ View imageView; ImageView image; TextView name; public ViewHolder(View view){ super(view); imageView = view; image = (ImageView) view.findViewById(R.id.image); name = (TextView) view.findViewById(R.id.name); } } public adapter(List<Image> list2){ list = list2; } public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType){ View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,parent,false); final ViewHolder holder = new ViewHolder(view); holder.imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int position = holder.getAbsoluteAdapterPosition(); Image image = list.get(position); Toast.makeText(view.getContext(), "你点击了"+image.getName(), Toast.LENGTH_SHORT).show(); } }); return holder; }...
}
效果如下:
希望本文章对你有帮助,如果你对Android开发感兴趣,请持续关注本专栏,帮助你从入门到项目实战,你将收获:Android基础开发、各种经典功能实现、项目实战、开发自己的APP、将APP上传应用商店、靠广告赚钱等等,持续更新ing......