学习Android之RecyclerView

 学习RecyclerView之前先回顾一下ListView。提升ListView的运行效率有两点:

  1. convertView:因为在FruitAdapter的getView()方法中,每次都将布局重新加载了一遍,当ListView快速滚动的时候,这就会成为性能的瓶颈。但是getView()方法中还有一个convertView参数,这个参数用于将之前加载好的布局进行缓存,以便之后进行重用,我们可以借助这个参数来进行性能优化。如果convertView为null,则使用LayoutInflater去加载布局;如果不为null,则直接对convertView进行重用。
  2. 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

 

posted @ 2022-03-12 20:57  PeacefulGemini  阅读(142)  评论(0)    收藏  举报
回顶部