Android - 强大的RecyclerView

本文详细介绍了Android中的RecyclerView控件,包括其优势、基本组件如RecyclerView、Adapter和ViewHolder的使用。通过实例展示了如何创建和绑定数据,实现列表滚动定位,以及设置水平和瀑布流布局。还提到了多item布局的概念,并给出了实现方式。最后,提及了第三方库BRVAH的强大功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

强大的RecyclerView

RecyclerView是androidx库的控件,低版本可能需要自行导入,但现在的版本是默认加上的
RecyclerView是一个强大的控件,主要用于替代ListView,ListView能实现的功能,他也能实现,他比ListView更好用,更方面,功能更加全面。

一、RecyclerView的使用主要涉及3个类:RecyclerView、Adapter,和ViewHolder

1.RecyclerView类

RecyclerView是ViewGroup的子类,每一个列表项都是作为一个View子对象显示的。这些
View子对象可简单可复杂,这取决于列表项要显示些什么。
RecyclerView顾名思义回收视图,他的一大特点就是回收,他只会显示屏幕能显示的几个布局,当滑动的时候,会将不要的视图回收,然后显示新的视图。而RecyclerView的任务仅仅只是回收和定位屏幕上的View,其余的功能都是交给Adapter和ViewHolder处理

2.ViewHolder

而ViewHolder所做的任务更少,就只有一个,就是用于容纳View视图,因为RecyclerView不会创建视图,所以视图都是ViewHolder创建的

3.Adapter

而上面的ViewHolder是由Adapter创建的,同时他是一个控制器,控制着RecyclerView。先创建好ViewHolder,绑定ViewHolder至模型层,然后从模型层取出数据,提供给RecyclerView显示

4.RecyclerView直接定位最后一个item

recyclerView.scrollToPosition(msgList.size - 1) ,直接定位到最后一个item

二、RecyclerView的使用

简单的吹完RecyclerView的理论,那就开始使用吧
这里我将RecyclerView用于显示学生数据

1.创建一个Student类

里面有4个数据,头像图片,名字,成绩与自我介绍

class Student(val name : String, val grade : Int, val headerImg : Int, val sign : String) {
}
2.创建一个item的视图

也就是列表中一项的视图
这里采用的是ConstraintLayout约束布局,不懂的小伙伴点这里 ↓
约束布局ConstraintLayout看这一篇就够了

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <ImageView
        android:id="@+id/header"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_margin="5dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>
    <TextView
        android:id="@+id/name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        app:layout_constraintRight_toLeftOf="@id/barrier"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@id/header"/>
    <TextView
        android:id="@+id/sign"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:textSize="12sp"
        app:layout_constraintLeft_toRightOf="@id/header"
        app:layout_constraintRight_toLeftOf="@id/barrier"
        app:layout_constraintTop_toBottomOf="@id/name"/>

    <androidx.constraintlayout.widget.Barrier
        android:id="@+id/barrier"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="16sp"
        app:barrierDirection="end"
        app:constraint_referenced_ids="name, sign"/>
    <TextView
        android:id="@+id/grade"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dp"
        app:layout_constraintLeft_toRightOf="@id/barrier"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>


</androidx.constraintlayout.widget.ConstraintLayout>
3.随便找几张图片作为头像
4.创建一个StudentAdapter适配器与ViewHolder
//创建一个StudentAdapter,构造函数传入一个Student列表数据,
// 同时继承RecyclerView.Adapter<>类,传入的泛型类是继承ViewHolder的类,所以下面的ViewHolder符合
class StudentAdapter(private val context : Context, private val studentList: List<Student>) : RecyclerView.Adapter<StudentAdapter.ViewHolder>() {
    //该类是继承RecyclerView的内部类ViewHolder
    //这里传入的view,通常都是一个item的最外部类,也就是上面创建的xml文件,用于获取该item中的所有控件实例
    inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val studentHeader : ImageView = view.findViewById(R.id.header)
        val studentName : TextView = view.findViewById(R.id.name)
        val studentSign : TextView = view.findViewById(R.id.sign)
        val studentGrade : TextView = view.findViewById(R.id.grade)
    }

    //看方法名就知道,这是用于创建ViewHolder实例的,同时将实例返回
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        //创建视图
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_student, parent, false)
        return ViewHolder(view)
    }

    //用于对item进行数据赋值
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val student = studentList[position]
        holder.studentHeader.setImageResource(student.headerImg)
        holder.studentName.text = student.name
        holder.studentSign.text = student.sign
        holder.studentGrade.text = "等级:${student.grade}"
        holder.studentGrade.setOnClickListener {//添加了一个点击成绩的点击事件,用于弹出一个Toast
            Toast.makeText(context, "${student.name}同学的等级是:${student.grade}", Toast.LENGTH_SHORT).show()
        }
    }

    //用于告诉RecyclerView一共有多少个item
    override fun getItemCount() = studentList.size
}
5.设置Activity的布局

创建好了RecyclerView要使用的内容, 就要创建一个RecyclerView了
修改activity_main布局,里面就只有一个占满全屏的RecyclerView

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val recyclerView : RecyclerView = findViewById(R.id.list) //获取recyclerView实例
        val layoutManager = LinearLayoutManager(this) //获取线性布局管理实例
        recyclerView.layoutManager = layoutManager //设置recyclerView的布局管理为线性布局管理
        val studentList : ArrayList<Student> = init() //创建一个学生列表
        val adapter = StudentAdapter(this, studentList) //创建一个StudentAdapter
        recyclerView.adapter = adapter //设置recyclerView的适配器为StudentAdapter的适配器

    }

    //获取一个学生列表
    fun init() : ArrayList<Student>{
        val students = ArrayList<Student>()
        var i = 1
        repeat(100){
            val resource = when { //主要用户显示不同的头像,嘿嘿
                i % 3 == 0 -> {
                    R.drawable.header1
                }
                i % 3 == 1 -> {
                    R.drawable.header2
                }
                else -> {
                    R.drawable.header3
                }
            }
            students.add(Student("我是刘同学${i}号", (1..10).random(), resource, "我就是我,我就是刘同学"))
            i += 1
        }
        return students
    }
}

这就大功告成了,一个简单的列表实现了
在这里插入图片描述

6.水平方向布局

主要是修改recyclerView.layoutManager = 布局管理
水平方向最简单,只需要修改这里既可

 val layoutManager = LinearLayoutManager(this) //获取线性布局管理实例
 layoutManager.orientation = LinearLayoutManager.HORIZONTAL
 recyclerView.layoutManager = layoutManager //设置recyclerView的布局管理为线性布局管理

修改item_student

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="100dp"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <ImageView
        android:id="@+id/header"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_margin="5dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
    <TextView
        android:id="@+id/grade"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dp"
        app:layout_constraintLeft_toRightOf="@id/header"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>
    <TextView
        android:id="@+id/name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        app:layout_constraintTop_toBottomOf="@id/header"
        app:layout_constraintLeft_toLeftOf="parent"/>
    <TextView
        android:id="@+id/sign"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:textSize="12sp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/name"/>

</androidx.constraintlayout.widget.ConstraintLayout>

在这里插入图片描述

7.瀑布流布局
val layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL) //获取瀑布流布局管理实例
recyclerView.layoutManager = layoutManager //设置recyclerView的布局管理为瀑布流布局管理

item_student布局

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <ImageView
        android:id="@+id/header"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_margin="5dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
    <TextView
        android:id="@+id/grade"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dp"
        app:layout_constraintLeft_toRightOf="@id/header"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>
    <TextView
        android:id="@+id/name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        app:layout_constraintTop_toBottomOf="@id/header"
        app:layout_constraintLeft_toLeftOf="parent"/>
    <TextView
        android:id="@+id/sign"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:textSize="12sp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/name"/>

</androidx.constraintlayout.widget.ConstraintLayout>

在这里插入图片描述

三、多item布局

我们上面的内容都是单item布局,什么意思呢,就是所有的数据都是使用同一个item的视图
而多item布局是可以使用多个不通的item布局,这里我们就使用左右不同的视图来区分
而我这里就简单举例,所以只用了不同的颜色背景与不同的布局来区分

1.设置左右item布局

首先是item_left_student

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/teal_200"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <ImageView
        android:id="@+id/header"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_margin="5dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
    <TextView
        android:id="@+id/grade"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dp"
        app:layout_constraintLeft_toRightOf="@id/header"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>
    <TextView
        android:id="@+id/name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        app:layout_constraintTop_toBottomOf="@id/header"
        app:layout_constraintLeft_toLeftOf="parent"/>
    <TextView
        android:id="@+id/sign"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:textSize="12sp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/name"/>

</androidx.constraintlayout.widget.ConstraintLayout>

item_right_student

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/purple_200"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <ImageView
        android:id="@+id/header"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_margin="5dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
    <TextView
        android:id="@+id/grade"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dp"
        app:layout_constraintRight_toLeftOf="@id/header"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"/>
    <TextView
        android:id="@+id/name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        app:layout_constraintTop_toBottomOf="@id/header"
        app:layout_constraintRight_toRightOf="parent"/>
    <TextView
        android:id="@+id/sign"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:textSize="12sp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/name"/>

</androidx.constraintlayout.widget.ConstraintLayout>
2.修改Student

这里主要是加了一个type用于区分左右显示

class Student(val name : String, val grade : Int, val headerImg : Int, val sign : String, val type : Int) {
}
3.修改Activity

//这里主要是在设置学生列表的时候随机获取1或者2,作为显示在左边还是右边的数据

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val recyclerView : RecyclerView = findViewById(R.id.list) //获取recyclerView实例
        val layoutManager = LinearLayoutManager(this) //获取线性布局管理实例
        recyclerView.layoutManager = layoutManager //设置recyclerView的布局管理为线性布局管理
        val studentList : ArrayList<Student> = init() //创建一个学生列表
        val adapter = StudentAdapter(this, studentList) //创建一个StudentAdapter
        recyclerView.adapter = adapter //设置recyclerView的适配器为StudentAdapter的适配器

    }

    //获取一个学生列表
    fun init() : ArrayList<Student>{
        val students = ArrayList<Student>()
        var i = 1
        repeat(100){
            val resource = when { //主要用户显示不同的头像,嘿嘿
                i % 3 == 0 -> {
                    R.drawable.header1
                }
                i % 3 == 1 -> {
                    R.drawable.header2
                }
                else -> {
                    R.drawable.header3
                }
            }
            //随机设为左右布局
            val type = (1..2).random()
            //添加一个Student对象到列表中
            students.add(Student("我是刘同学${i}号", (1..10).random(), resource, "我就是我,我就是刘同学", type))
            i += 1
        }
        return students
    }
}
4.修改StudentAdapter类

主要添加了一个getItemViewType()方法来返回不同的viewType进而在onCreateViewHolder返回不同的View视图

//创建一个StudentAdapter,构造函数传入一个Student列表数据,
// 同时继承RecyclerView.Adapter<>类,传入的泛型类是继承ViewHolder的类,所以下面的ViewHolder符合
class StudentAdapter(private val context : Context, private val studentList: List<Student>) : RecyclerView.Adapter<StudentAdapter.ViewHolder>() {
    //设置静态变量,用于设置viewType类型
    companion object{
        private const val TYPE_LEFT = 1111
        private const val TYPE_RIGHT = 2222
    }
    //该类是继承RecyclerView的内部类ViewHolder
    //这里传入的view,通常都是一个item的最外部类,也就是上面创建的xml文件,用于获取该item中的所有控件实例
    inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val studentHeader : ImageView = view.findViewById(R.id.header)
        val studentName : TextView = view.findViewById(R.id.name)
        val studentSign : TextView = view.findViewById(R.id.sign)
        val studentGrade : TextView = view.findViewById(R.id.grade)
    }

    //看方法名就知道,这是用于创建ViewHolder实例的,同时将实例返回
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        //创建视图,判断viewType类型,从而返回对应的视图
        return if(viewType == TYPE_LEFT) {
            val view = LayoutInflater.from(parent.context)
                .inflate(R.layout.item_left_student, parent, false)
            ViewHolder(view)
        } else{
            val view = LayoutInflater.from(parent.context)
                .inflate(R.layout.item_right_student, parent, false)
            ViewHolder(view)
        }

    }

    //用于对item进行数据赋值
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        //这里数据不变,所以就直接复制两边,因为item的数据完全不一样,所以可以判断类型,然后单独设置数据
        if(holder.itemViewType == TYPE_LEFT) {
            val student = studentList[position]
            holder.studentHeader.setImageResource(student.headerImg)
            holder.studentName.text = student.name
            holder.studentSign.text = student.sign
            holder.studentGrade.text = "等级:${student.grade}"
            holder.studentGrade.setOnClickListener { //添加了一个点击成绩的点击事件,用于弹出一个Toast
                Toast.makeText(
                    context,
                    "这是左边的数据",
                    Toast.LENGTH_SHORT
                ).show()
            }
        } else {
            val student = studentList[position]
            holder.studentHeader.setImageResource(student.headerImg)
            holder.studentName.text = student.name
            holder.studentSign.text = student.sign
            holder.studentGrade.text = "等级:${student.grade}"
            holder.studentGrade.setOnClickListener { //添加了一个点击成绩的点击事件,用于弹出一个Toast
                Toast.makeText(
                    context,
                    "这是右边的数据",
                    Toast.LENGTH_SHORT
                ).show()
            }
        }
    }

    //用于告诉RecyclerView一共有多少个item
    override fun getItemCount() = studentList.size

    //通过某个变量,判断使用哪个item,返回设置好int变量
    override fun getItemViewType(position: Int): Int {
        val student = studentList[position]
        return if(student.type == 1){
            TYPE_LEFT
        } else {
            TYPE_RIGHT
        }
    }
}

运行效果
在这里插入图片描述

四、强大的BRVAH

BaseRecyclerViewAdapterHelper是一个强大的第三方框架,正在了解,所以暂不写笔记
大伙可以自个去看看
GitHub链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值