具有 2 种视图类型的 kotlin recyclerview
kotlin recyclerview with 2 view types
在每第 5 个项目之后,我想要加载一个按钮视图。
override fun getItemViewType(position: Int): Int {
if (position % 5 == 0 && position != 0) {
return R.layout.button10th
} else {
return R.layout.checkitout
}
}
当我 运行 它时,这是拿走了我的第 5 件物品。
我怎样才能在不拿走我的任何阵列项目的情况下实现这一目标?我需要修复我的 getItemCount 吗?
override fun getItemCount(): Int {
return lists.size
}
我希望它看起来像下面这样。
1.约翰
2.迈克
3.克里斯
4.简
5.起诉
6. 可点击按钮
在使用多视图 RecyclerViews 一段时间后,这是我最好的方法(它可以防止错误并且实现得当):
为您的两种项目类型创建两个 viewHolder classes,每个都有一个 bind() 函数:
class NameViewHolder(itemView: View) :
RecyclerView.ViewHolder(itemView) {
fun bind(cell: Cell) {
//Do your bindViewHolder logic in here
}
}
由于我们有多个视图类型,因此有多个 viewHolder,我们需要创建一个普通的 java 对象来保存公共信息。我调用了我的 Cell()。称它为任何适合你的需要。我们会解决的。
所以现在你有两个 viewHolder classes:NameViewHolder()
和 ButtonViewHolder()
.
现在让我们创建我们的 Cell class 和对象:
open class Cell {
fun identifier() = this::class.java.name.hashCode()
}
class CellName(
val name: String
) : Cell()
class CellButton(
val buttonText: String
) : Cell()
让我解释一下:所以我创建了一个全局 Cell() 对象,其中有一个标识符函数,它给我一个 class 哈希。这个函数稍后会为我们服务,以获取我们的视图类型。在我的 RecyclerView 中,我不使用 Int 或其他东西来识别我的视图类型,而是使用我的对象 class 本身的散列。散列是每个 class 的唯一字符串。因此,如果我的适配器在其项目列表中偶然发现一个 CellName() 对象,则 recyclerView 使用我的 identifier() 函数获取其哈希值,并意识到此视图类型是名称,而不是按钮(来自您的示例多于)。
其他 classes 扩展了全局 Cell() class 并具有自定义的个人逻辑。给他们任何你喜欢或需要的参数。
现在在我们的适配器中,我们将像这样添加我们的单元格列表作为参数:
class MyAdapter(
var items: ArrayList<Cell> = ArrayList()
): RecyclerView.Adapter<RecyclerView.ViewHolder>() {
确保完全按照上面的方式实现 RecyclerView.Adapter,否则多视图将无法工作。
现在,选择您的视图类型的 getItemViewType 覆盖方法将如下所示:
override fun getItemViewType(position: Int) = items[position].identifier()
如您所见,我们在这里使用我之前讲过的 identifier() 函数,让适配器知道根据 Cell() class 哈希选择什么视图类型。
现在是您的视图膨胀的 onCreateViewHolder:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
RecyclerView.ViewHolder {
return when (viewType) {
CellName::class.java.name.hashCode() ->
NameViewHolder(parent.inflate(R.layout.your_name_view)
CellButton::class.java.name.hashCode() ->
ButtonViewHolder(parent.inflate(R.layout.your_button_view)
}
}
现在,当适配器找到名称视图类型时,它会使用所需的布局扩展 NameViewHolder,对于带有 ButtonViewHolder 的按钮也是如此。接下来,onBindViewHoder:
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (val item = items[holder.adapterPosition]) {
is CellName -> (holder as NameViewHolder).bind(item)
is CellButton -> (holder as ButtonViewHolder).bind(item)
}}
基本上对于每种类型的单元格 class,您可以从 viewHolder classes.
访问绑定函数
recyclerView 适配器就是这样。这是到目前为止的整个文件(接下来我们将继续创建您的单元格列表):
class MyAdapter(
private var items: ArrayList<Cell> = ArrayList()
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun getItemCount(): Int = items.size
override fun getItemViewType(position: Int) = items[position].identifier()
@Suppress("HasPlatformType")
fun ViewGroup.inflate(@LayoutRes resId: Int) = LayoutInflater.from(this.context)
.inflate(resId, this, false)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
RecyclerView.ViewHolder {
return when (viewType) {
CellName::class.java.name.hashCode() ->
NameViewHolder(parent.inflate(R.layout.your_name_view))
CellButton::class.java.name.hashCode() ->
ButtonViewHolder(parent.inflate(R.layout.your_button_view))
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (val item = items[holder.adapterPosition]) {
is CellName -> (holder as NameViewHolder)
.bind(item)
is CellButton -> (holder as ButtonViewHolder)
.bind(item)
}
}
}
class NameViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(cell: Cell) {
//Do your bindViewHolder logic in here
}
}
class ButtonViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(cell: Cell) {
//Do your bindViewHolder logic in here
}
}
open class Cell {
fun identifier() = this::class.java.name.hashCode()
}
class CellName(
val name: String
) : Cell()
class CellButton(
val buttonText: String
) : Cell()
请确保滚动上面的文字,因为它太大了。此外,
@Suppress("HasPlatformType")
fun ViewGroup.inflate(@LayoutRes resId: Int) = LayoutInflater.from(this.context)
.inflate(resId, this, false)
是一个 Kotlin 扩展函数,可以使布局 inflation 更快。按原样使用。
接下来,您的单元格列表创建:
fun createCells(
// Whatever params.
): ArrayList(Cell){
val cellList = ArrayList<Cell>()
var firstCell = CellName("Christina")
val secondCell = CellName("Mary")
val thirdCell = CellButton("View More!")
cellList.add(firstCell)
cellList.add(secondCell)
cellList.add(thirdCell)
// Note that here you can do whatever you want, use forEach, for, anything to
create a full list of Cells with your desired information.
return cellList
}
在任何 activity/fragment 有该适配器的地方使用此功能。
val myAdapter = MyAdapter(createCells())
recyclerView.adapter = myAdapter
就是这样。您可以根据需要随意自定义您的单元格和视图类型。请记住,对于您在 recyclerView 中需要的每个新视图类型,您必须为其创建一个单元格 class 和一个视图持有者 class。
这是我关于多种视图类型的完整教程。并回答您关于如何执行此操作的明确问题:
if (position % 5 == 0 && position != 0) {
return R.layout.button10th
} else {
return R.layout.checkitout
} //Your code from your question here
...你没有。在 recyclerView 中,您不再需要这种逻辑。适配器只能接收 Cells 列表,仅此而已。这只会防止大量错误并使您的代码更清晰,更易于阅读。您只需在 createCells() 函数中创建单元格,例如:
something.forEachIndexed {index, item ->
if(index % 5 == 0 && position != 0)
cellList.add(CellButton("button_stuff"))
else
cellList.add(CellName("blabla"))
}
您再也不用担心商品编号和位置了。只需使用 createCells() 函数来完成您的整个逻辑,但 return 一个完整的列表和适配器知道该做什么。
如果您想知道如何使用 bindViewHolder 中的 bind() 函数,您可以在您的适配器中执行您通常在该代码块中执行的任何操作,例如在 textView 和按钮中设置文本,设置使用 Glide 或通过资源链接创建您的按钮功能的图像。我实际上会解释如何实现按钮功能和 bind():
还记得我们是如何在我们的单元格对象中设置我们想要的信息的吗?
class ButtonViewHolder(itemView: View) :
RecyclerView.ViewHolder(itemView) {
fun bind(cell: Cell) {
//Do your bindViewHolder logic in here
}
}
在这里您可以访问该对象,所以让我们创建一个按钮并为其添加一个回调。为此,您必须使用回调变量更新绑定函数。
fun bind(cell: Cell, buttonCallback: (() -> Unit)) {
//Do your bindViewHolder logic in here
itemView.yourXMLTitleWhatever.text = cell.titleText //(if you have a title for example)
itemView.yourXMLButton.setOnClickListener {
buttonCallback.invoke()
}
}
调用函数告诉您的回调按钮已被按下。现在为了使回调工作,我们需要在您的适配器中将回调变量声明为 public。所以在你的适配器里面添加这个:
class MyAdapter(
private var items: ArrayList<Cell> = ArrayList()
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
var buttonCallback: (() -> Unit) = {}
(...)
并且不要忘记将 var 作为参数添加到适配器中的绑定调用中:
所以代替:
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (val item = items[holder.adapterPosition]) {
is CellName -> (holder as NameViewHolder).bind(item)
is CellButton -> (holder as ButtonViewHolder).bind(item)
}}
我们将有:
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (val item = items[holder.adapterPosition]) {
is CellName -> (holder as NameViewHolder).bind(item)
is CellButton -> (holder as ButtonViewHolder).bind(item, buttonCallback)
}}
基本上,这种类型的回调变量是接口的 Kotlin 快捷方式,当您创建接口来处理适配器点击时,它会做同样的事情,在 Java 中。
但我们还没有完成,请确保您的适配器回调变量不是私有的,并在您的 ACTIVITY 中执行此操作以访问它:
myAdapter.onButtonClick = {
//add your button click functionality here (like activity change or anything).
}
其中 myAdapter = MyAdapter(cellList)
希望我有所帮助。
我发现实现这一点的最简单方法是将 model
与 ViewHolder
相关联。我的意思是什么。
我的方法的工作原理是删除何时将每个 ViewHolder
从适配器填充到我们的元素列表中的决定。
假设我们想要显示一个名称列表,并且每第 5 个项目我们想要显示一个广告(只是一个例子,它可以是任何东西)
val elements = listOf("Name #1", "Name #2", "Name #3", "Name #4", AdModel("our ad"), "Name #5")
现在在适配器内部,我们首先说我们扩展了泛型ViewHolder
class RecyclerView.Adapter<RecyclerView.ViewHolder>()
。
之后,我们要覆盖 3 个方法。
getItemViewType
在这里我们将决定哪个布局文件与每个 model
我们将使用实例检查和 return 我们要根据类型显示的布局文件来做到这一点。
override fun getItemViewType(position: Int): Int {
val element = elements[position] // assuming your list is called "elements"
return when (element) {
is String -> R.layout.name_layout_file
is AdModel -> R.layout.ad_layout_file
else -> throw IllegalArgumentException("Unsupported type") // in case populated with a model we don't know how to display.
}
}
onCreateViewHolder
您需要为每个要显示的类型创建一个 ViewHolder
class。
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
R.layout.name_layout_file -> NameViewHolder(inflater.inflate(viewType, parent, false))
R.layout.ad_layout_file -> AdViewHolder(inflater.inflate(viewType, parent, false))
else -> throw IllegalArgumentException("Unsupported layout") // in case populated with a model we don't know how to display.
}
}
onBindViewHolder
在这里我们可以很容易的施展我们的ViewHolder
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val element = elements[position] // assuming your list is called "elements"
when (holder) {
is NameViewHolder -> {
val name = element as String
// bind NameViewHolder
}
is AdViewHolder -> {
val adModel = element as AdModel
// bind AdViewHolder
}
}
}
您的完整适配器应如下所示:
class SampleAdapter(val elements: List<Any>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
R.layout.name_layout_file -> NameViewHolder(inflater.inflate(viewType, parent, false))
R.layout.ad_layout_file -> AdViewHolder(inflater.inflate(viewType, parent, false))
else -> throw IllegalArgumentException("Unsupported layout") // in case populated with a model we don't know how to display.
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val element = elements[position] // assuming your list is called "elements"
when (holder) {
is NameViewHolder -> {
val name = element as String
// bind NameViewHolder
}
is AdViewHolder -> {
val adModel = element as AdModel
// bind AdViewHolder
}
}
}
override fun getItemViewType(position: Int): Int {
val element = elements[position] // assuming your list is called "elements"
return when (element) {
is String -> R.layout.name_layout_file
is AdModel -> R.layout.ad_layout_file
else -> throw IllegalArgumentException("Unsupported type") // in case populated with a model we don't know how to display.
}
}
}
当您加载适配器时,您将其与多类型列表一起加载,一切正常。
最大的优点是你不局限于特定的类型,添加更多视图类型非常容易。
但是,如果您想保存所有这些工作,我编写了一个库,该库使用注释处理在编译时生成 single/multi-type 适配器。
该库会生成您需要的所有内容,包括 findViewById
并为您提供实现适配器所需编写的最少代码。
你可以在这里查看:Gencycler
在每第 5 个项目之后,我想要加载一个按钮视图。
override fun getItemViewType(position: Int): Int {
if (position % 5 == 0 && position != 0) {
return R.layout.button10th
} else {
return R.layout.checkitout
}
}
当我 运行 它时,这是拿走了我的第 5 件物品。 我怎样才能在不拿走我的任何阵列项目的情况下实现这一目标?我需要修复我的 getItemCount 吗?
override fun getItemCount(): Int {
return lists.size
}
我希望它看起来像下面这样。 1.约翰 2.迈克 3.克里斯 4.简 5.起诉 6. 可点击按钮
在使用多视图 RecyclerViews 一段时间后,这是我最好的方法(它可以防止错误并且实现得当):
为您的两种项目类型创建两个 viewHolder classes,每个都有一个 bind() 函数:
class NameViewHolder(itemView: View) :
RecyclerView.ViewHolder(itemView) {
fun bind(cell: Cell) {
//Do your bindViewHolder logic in here
}
}
由于我们有多个视图类型,因此有多个 viewHolder,我们需要创建一个普通的 java 对象来保存公共信息。我调用了我的 Cell()。称它为任何适合你的需要。我们会解决的。
所以现在你有两个 viewHolder classes:NameViewHolder()
和 ButtonViewHolder()
.
现在让我们创建我们的 Cell class 和对象:
open class Cell {
fun identifier() = this::class.java.name.hashCode()
}
class CellName(
val name: String
) : Cell()
class CellButton(
val buttonText: String
) : Cell()
让我解释一下:所以我创建了一个全局 Cell() 对象,其中有一个标识符函数,它给我一个 class 哈希。这个函数稍后会为我们服务,以获取我们的视图类型。在我的 RecyclerView 中,我不使用 Int 或其他东西来识别我的视图类型,而是使用我的对象 class 本身的散列。散列是每个 class 的唯一字符串。因此,如果我的适配器在其项目列表中偶然发现一个 CellName() 对象,则 recyclerView 使用我的 identifier() 函数获取其哈希值,并意识到此视图类型是名称,而不是按钮(来自您的示例多于)。 其他 classes 扩展了全局 Cell() class 并具有自定义的个人逻辑。给他们任何你喜欢或需要的参数。
现在在我们的适配器中,我们将像这样添加我们的单元格列表作为参数:
class MyAdapter(
var items: ArrayList<Cell> = ArrayList()
): RecyclerView.Adapter<RecyclerView.ViewHolder>() {
确保完全按照上面的方式实现 RecyclerView.Adapter,否则多视图将无法工作。
现在,选择您的视图类型的 getItemViewType 覆盖方法将如下所示:
override fun getItemViewType(position: Int) = items[position].identifier()
如您所见,我们在这里使用我之前讲过的 identifier() 函数,让适配器知道根据 Cell() class 哈希选择什么视图类型。
现在是您的视图膨胀的 onCreateViewHolder:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
RecyclerView.ViewHolder {
return when (viewType) {
CellName::class.java.name.hashCode() ->
NameViewHolder(parent.inflate(R.layout.your_name_view)
CellButton::class.java.name.hashCode() ->
ButtonViewHolder(parent.inflate(R.layout.your_button_view)
}
}
现在,当适配器找到名称视图类型时,它会使用所需的布局扩展 NameViewHolder,对于带有 ButtonViewHolder 的按钮也是如此。接下来,onBindViewHoder:
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (val item = items[holder.adapterPosition]) {
is CellName -> (holder as NameViewHolder).bind(item)
is CellButton -> (holder as ButtonViewHolder).bind(item)
}}
基本上对于每种类型的单元格 class,您可以从 viewHolder classes.
访问绑定函数recyclerView 适配器就是这样。这是到目前为止的整个文件(接下来我们将继续创建您的单元格列表):
class MyAdapter(
private var items: ArrayList<Cell> = ArrayList()
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun getItemCount(): Int = items.size
override fun getItemViewType(position: Int) = items[position].identifier()
@Suppress("HasPlatformType")
fun ViewGroup.inflate(@LayoutRes resId: Int) = LayoutInflater.from(this.context)
.inflate(resId, this, false)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
RecyclerView.ViewHolder {
return when (viewType) {
CellName::class.java.name.hashCode() ->
NameViewHolder(parent.inflate(R.layout.your_name_view))
CellButton::class.java.name.hashCode() ->
ButtonViewHolder(parent.inflate(R.layout.your_button_view))
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (val item = items[holder.adapterPosition]) {
is CellName -> (holder as NameViewHolder)
.bind(item)
is CellButton -> (holder as ButtonViewHolder)
.bind(item)
}
}
}
class NameViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(cell: Cell) {
//Do your bindViewHolder logic in here
}
}
class ButtonViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(cell: Cell) {
//Do your bindViewHolder logic in here
}
}
open class Cell {
fun identifier() = this::class.java.name.hashCode()
}
class CellName(
val name: String
) : Cell()
class CellButton(
val buttonText: String
) : Cell()
请确保滚动上面的文字,因为它太大了。此外,
@Suppress("HasPlatformType")
fun ViewGroup.inflate(@LayoutRes resId: Int) = LayoutInflater.from(this.context)
.inflate(resId, this, false)
是一个 Kotlin 扩展函数,可以使布局 inflation 更快。按原样使用。
接下来,您的单元格列表创建:
fun createCells(
// Whatever params.
): ArrayList(Cell){
val cellList = ArrayList<Cell>()
var firstCell = CellName("Christina")
val secondCell = CellName("Mary")
val thirdCell = CellButton("View More!")
cellList.add(firstCell)
cellList.add(secondCell)
cellList.add(thirdCell)
// Note that here you can do whatever you want, use forEach, for, anything to
create a full list of Cells with your desired information.
return cellList
}
在任何 activity/fragment 有该适配器的地方使用此功能。
val myAdapter = MyAdapter(createCells())
recyclerView.adapter = myAdapter
就是这样。您可以根据需要随意自定义您的单元格和视图类型。请记住,对于您在 recyclerView 中需要的每个新视图类型,您必须为其创建一个单元格 class 和一个视图持有者 class。 这是我关于多种视图类型的完整教程。并回答您关于如何执行此操作的明确问题:
if (position % 5 == 0 && position != 0) {
return R.layout.button10th
} else {
return R.layout.checkitout
} //Your code from your question here
...你没有。在 recyclerView 中,您不再需要这种逻辑。适配器只能接收 Cells 列表,仅此而已。这只会防止大量错误并使您的代码更清晰,更易于阅读。您只需在 createCells() 函数中创建单元格,例如:
something.forEachIndexed {index, item ->
if(index % 5 == 0 && position != 0)
cellList.add(CellButton("button_stuff"))
else
cellList.add(CellName("blabla"))
}
您再也不用担心商品编号和位置了。只需使用 createCells() 函数来完成您的整个逻辑,但 return 一个完整的列表和适配器知道该做什么。
如果您想知道如何使用 bindViewHolder 中的 bind() 函数,您可以在您的适配器中执行您通常在该代码块中执行的任何操作,例如在 textView 和按钮中设置文本,设置使用 Glide 或通过资源链接创建您的按钮功能的图像。我实际上会解释如何实现按钮功能和 bind():
还记得我们是如何在我们的单元格对象中设置我们想要的信息的吗?
class ButtonViewHolder(itemView: View) :
RecyclerView.ViewHolder(itemView) {
fun bind(cell: Cell) {
//Do your bindViewHolder logic in here
}
}
在这里您可以访问该对象,所以让我们创建一个按钮并为其添加一个回调。为此,您必须使用回调变量更新绑定函数。
fun bind(cell: Cell, buttonCallback: (() -> Unit)) {
//Do your bindViewHolder logic in here
itemView.yourXMLTitleWhatever.text = cell.titleText //(if you have a title for example)
itemView.yourXMLButton.setOnClickListener {
buttonCallback.invoke()
}
}
调用函数告诉您的回调按钮已被按下。现在为了使回调工作,我们需要在您的适配器中将回调变量声明为 public。所以在你的适配器里面添加这个:
class MyAdapter(
private var items: ArrayList<Cell> = ArrayList()
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
var buttonCallback: (() -> Unit) = {}
(...)
并且不要忘记将 var 作为参数添加到适配器中的绑定调用中:
所以代替:
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (val item = items[holder.adapterPosition]) {
is CellName -> (holder as NameViewHolder).bind(item)
is CellButton -> (holder as ButtonViewHolder).bind(item)
}}
我们将有:
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (val item = items[holder.adapterPosition]) {
is CellName -> (holder as NameViewHolder).bind(item)
is CellButton -> (holder as ButtonViewHolder).bind(item, buttonCallback)
}}
基本上,这种类型的回调变量是接口的 Kotlin 快捷方式,当您创建接口来处理适配器点击时,它会做同样的事情,在 Java 中。
但我们还没有完成,请确保您的适配器回调变量不是私有的,并在您的 ACTIVITY 中执行此操作以访问它:
myAdapter.onButtonClick = {
//add your button click functionality here (like activity change or anything).
}
其中 myAdapter = MyAdapter(cellList)
希望我有所帮助。
我发现实现这一点的最简单方法是将 model
与 ViewHolder
相关联。我的意思是什么。
我的方法的工作原理是删除何时将每个 ViewHolder
从适配器填充到我们的元素列表中的决定。
假设我们想要显示一个名称列表,并且每第 5 个项目我们想要显示一个广告(只是一个例子,它可以是任何东西)
val elements = listOf("Name #1", "Name #2", "Name #3", "Name #4", AdModel("our ad"), "Name #5")
现在在适配器内部,我们首先说我们扩展了泛型ViewHolder
class RecyclerView.Adapter<RecyclerView.ViewHolder>()
。
之后,我们要覆盖 3 个方法。
getItemViewType
在这里我们将决定哪个布局文件与每个 model
我们将使用实例检查和 return 我们要根据类型显示的布局文件来做到这一点。
override fun getItemViewType(position: Int): Int {
val element = elements[position] // assuming your list is called "elements"
return when (element) {
is String -> R.layout.name_layout_file
is AdModel -> R.layout.ad_layout_file
else -> throw IllegalArgumentException("Unsupported type") // in case populated with a model we don't know how to display.
}
}
onCreateViewHolder
您需要为每个要显示的类型创建一个 ViewHolder
class。
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
R.layout.name_layout_file -> NameViewHolder(inflater.inflate(viewType, parent, false))
R.layout.ad_layout_file -> AdViewHolder(inflater.inflate(viewType, parent, false))
else -> throw IllegalArgumentException("Unsupported layout") // in case populated with a model we don't know how to display.
}
}
onBindViewHolder
在这里我们可以很容易的施展我们的ViewHolder
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val element = elements[position] // assuming your list is called "elements"
when (holder) {
is NameViewHolder -> {
val name = element as String
// bind NameViewHolder
}
is AdViewHolder -> {
val adModel = element as AdModel
// bind AdViewHolder
}
}
}
您的完整适配器应如下所示:
class SampleAdapter(val elements: List<Any>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
R.layout.name_layout_file -> NameViewHolder(inflater.inflate(viewType, parent, false))
R.layout.ad_layout_file -> AdViewHolder(inflater.inflate(viewType, parent, false))
else -> throw IllegalArgumentException("Unsupported layout") // in case populated with a model we don't know how to display.
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val element = elements[position] // assuming your list is called "elements"
when (holder) {
is NameViewHolder -> {
val name = element as String
// bind NameViewHolder
}
is AdViewHolder -> {
val adModel = element as AdModel
// bind AdViewHolder
}
}
}
override fun getItemViewType(position: Int): Int {
val element = elements[position] // assuming your list is called "elements"
return when (element) {
is String -> R.layout.name_layout_file
is AdModel -> R.layout.ad_layout_file
else -> throw IllegalArgumentException("Unsupported type") // in case populated with a model we don't know how to display.
}
}
}
当您加载适配器时,您将其与多类型列表一起加载,一切正常。
最大的优点是你不局限于特定的类型,添加更多视图类型非常容易。
但是,如果您想保存所有这些工作,我编写了一个库,该库使用注释处理在编译时生成 single/multi-type 适配器。
该库会生成您需要的所有内容,包括 findViewById
并为您提供实现适配器所需编写的最少代码。
你可以在这里查看:Gencycler