学习Android之RecyclerView
学习RecyclerView之前先回顾一下ListView。提升ListView的运行效率有两点:
- convertView:因为在FruitAdapter的getView()方法中,每次都将布局重新加载了一遍,当ListView快速滚动的时候,这就会成为性能的瓶颈。但是getView()方法中还有一个convertView参数,这个参数用于将之前加载好的布局进行缓存,以便之后进行重用,我们可以借助这个参数来进行性能优化。如果convertView为null,则使用LayoutInflater去加载布局;如果不为null,则直接对convertView进行重用。
- ViewHolder:虽然用了法一就不会再重复去加载布局,但是每次在getView()方法中仍然会调用View的findViewById()方法来获取一次控件的实例。就新增了一个内部类ViewHolder,用于对ImageView和TextView的控件实例进行缓存。当convertView为null的时候,创建一个ViewHolder对象,并将控件的实例存放在ViewHolder里,然后调用View的setTag()方法,将ViewHolder对象存储在View中。当convertView不为null的时候,则调用View的getTag()方法,把ViewHolder重新取出。
而RecyclerView就帮我们做好了这些优化。
添加依赖
RecyclerView属于新增控件,需要在项目的build.gradle中添加RecyclerView库的依赖。
implementation 'androidx.recyclerview:recyclerview:1.1.0'
创建类和子项布局文件
新建实体类

新建fruit_item.xml,作为子项布局
新建适配器
新建FruitAdapter类,继承自RecyclerView.Adapter,并将泛型指定为FruitAdapter.ViewHolder。
其中,ViewHolder是我们在FruitAdapter中定义的一个内部类。Kotlin中使用inner class关键字来定义内部类。
ViewHolder的作用将所有控件的实例都缓存在了ViewHolder里,就没有必要每次都通过findViewById()方法来获取控件实例了。

首先定义了一个内部类ViewHolder,它要继承自RecyclerView.ViewHolder。然后ViewHolder的主构造函数中要传入一个View参数,这个参数通常就是RecyclerView子项的最外层布局,那么我们就可以通过findViewById()方法来获取布局中ImageView和TextView的实例了。
由于FruitAdapter是继承自RecyclerView.Adapter的,那么就必须重写onCreateViewHolder()、onBindViewHolder()和getItemCount()这3个方法。
onCreateViewHolder()方法是用于创建ViewHolder实例的,我们在这个方法中将fruit_item布局加载进来,然后创建一个ViewHolder实例,并把加载出来的布局传入构造函数当中,最后将ViewHolder的实例返回。
onBindViewHolder()方法用于对RecyclerView子项的数据进行赋值,会在每个子项被滚动到屏幕内的时候执行,这里我们通过position参数得到当前项的Fruit实例,然后再将数据设置到ViewHolder的ImageView和TextView当中即可。
getItemCount()方法就非常简单了,它用于告诉RecyclerView一共有多少子项,直接返回数据源的长度就可以了。
使用RecyclerView

先创建了一个LinearLayoutManager对象,用于指定RecyclerView的布局方式。
接下来创建FruitAdapter的实例,并将水果数据传入FruitAdapter的构造函数中,最后调用RecyclerView的setAdapter()方法。
实现横向滚动布局
ListView的扩展性并不好,它只能实现纵向滚动的效果。但是RecyclerView可以。
先修改fruit_item布局,要实现横向滚动的话,应该把fruit_item里的元素改成垂直排列才合理,并把LinearLayout宽度设为固定值。
在MainActivity中只加入了一行代码,调用LinearLayoutManager的setOrientation()方法设置布局的排列方向。

默认是纵向排列的。
实现瀑布流布局
首先修改fruit_item.xml,将LinearLayout的宽度改回了match_parent,因为瀑布流布局的宽度应该是根据布局的列数来自动适配的。
接着修改MainActivity中的代码:
val layoutManager = StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL)
这个函数接收两个参数:第一个是指定布局的列数,第二个用于指定布局的排列方向。
RecyclerView的点击事件
不过不同于ListView的是,RecyclerView并没有提供类似于setOnItemClickListener()这样的注册监听器方法,而是需要我们自己给子项具体的View去注册点击事件。
因为这样可以实现点击子项里具体的某一个按钮。
修改FruitAdapter中的代码
在onCreateViewHolder()方法中注册点击事件:
val view = LayoutInflater.from(parent.context) .inflate(R.layout.fruit_item,parent,false) val viewHolder = ViewHolder(view) //最外层布局点击事件 viewHolder.itemView.setOnClickListener { val position = viewHolder.adapterPosition val fruit = fruitList[position] Toast.makeText(parent.context,"you clicked view ${fruit.name}", Toast.LENGTH_SHORT).show() } //ImageView点击事件 viewHolder.fruitImage.setOnClickListener { val position = viewHolder.adapterPosition val fruit = fruitList[position] Toast.makeText(parent.context,"you clicked image ${fruit.name}", Toast.LENGTH_SHORT).show() } return viewHolder

浙公网安备 33010602011771号