你是否会经常见到在同一个 RecyclerView 列表中加载多种不同的布局效果?最近写了一篇 ConcatAdapter 相关内容,发现虽然之前一直在使用多类型视图列表,但从未记录过,故重新记录于此
RecyclerView基础
RecyclerView扩展
RecyclerView相关功能
- Android进阶之路 - RecyclerView左划删除(SwipeRecyclerView的简单使用 17年)
- Android进阶之路 - RecyclerView列表置顶、滑动到指定条目(18年)
- Android进阶之路 - RecyclerView列表自动无限水平滚动(21年)
- Android进阶之路 - 双列表联动效果(18年)
那年花开
实现效果 (不同背景色代表不同 ViewType
视图)
前置要求
包含数据结构
、视图结构
前置结构
问:在列表中你如何判断某条数据加载对应视图?
答:不论如何,数据结构中一定有一个类似type的字段用于区分展示哪种类型的视图
kotlin
package com.example.concatadatper
class MoreTypeBean(var data: String, var type: Int)
前置视图
列表中有几种视图类型,一般就意味着有几种对应的
layout布局
和ViewHolder
Tip
- 为了更直观查看实现效果,简化了视图类型对应的
layout
布局 - 当前不同类型的
ViewHolder
写在了Adapter
中,如有需求也可以抽出来
item_first (视图类型一)
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="50dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="#f65478"
android:textColor="#ffffff"
android:id="@+id/tv_first"
android:text="First" />
</LinearLayout>
item_second(视图类型二)
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="50dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="#e98745"
android:textColor="#ffffff"
android:id="@+id/tv_second"
android:text="Second" />
</LinearLayout>
核心实现
常规的多类型视图列表, RecyclerView
一般只有一个 Adapter
,通过重写内部 onCreateViewHolder
、onBindViewHolder
、getItemViewType
方法,从而加载不同的视图,处理不同的逻辑,具体如下
kotlin
package com.example.concatadatper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
class MoreViewAdapter(private val dataList: MutableList<MoreTypeBean>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val FIRST_TYPE = 1
private val SECOND_TYPE = 2
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
//根据不同itemType加载不同的ViewHolder
return if (viewType == FIRST_TYPE) {
val firstView = LayoutInflater.from(parent.context).inflate(R.layout.item_first, parent, false)
FirstViewHolder(firstView)
} else {
val secondView = LayoutInflater.from(parent.context).inflate(R.layout.item_second, parent, false)
SecondViewHolder(secondView)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
//不同的视图类型,逻辑也有所不同
val currentInfo = dataList[position]
if (currentInfo.type == FIRST_TYPE) {
(holder as FirstViewHolder).firstText.text = currentInfo.data
} else {
(holder as SecondViewHolder).secondText.text = currentInfo.data
}
}
override fun getItemCount(): Int {
return dataList.size
}
/**
* Tip:记得重写该处逻辑,否则onCreateViewHolder返回可能有问题
* */
override fun getItemViewType(position: Int): Int {
return dataList[position].type
}
/**
* 第一种视图类型
* */
class FirstViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var firstText: TextView
init {
firstText = itemView.findViewById<TextView>(R.id.tv_first)
}
}
/**
* 第二种视图类型
* */
class SecondViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var secondText: TextView
init {
secondText = itemView.findViewById<TextView>(R.id.tv_second)
}
}
}
使用方式
kotlin
package com.example.concatadatper
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
class MainActivity : AppCompatActivity() {
private var totalList: MutableList<MoreTypeBean> = mutableListOf<MoreTypeBean>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//数据模拟(当前有1、2俩种类型,对应的背景色)
totalList.add(MoreTypeBean("窗前明月光", 1))
totalList.add(MoreTypeBean("昨日已熬夜", 2))
totalList.add(MoreTypeBean("老夫思故乡", 1))
totalList.add(MoreTypeBean("今日又熬夜", 2))
totalList.add(MoreTypeBean("明日得早睡", 2))
//视图关联
val mRv = findViewById<RecyclerView>(R.id.rv)
val moreViewAdapter = MoreViewAdapter(totalList)
mRv.layoutManager = LinearLayoutManager(this)
mRv.adapter = moreViewAdapter
}
}
activity_main
xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat 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/rv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.appcompat.widget.LinearLayoutCompat>