在Recyclerview Kotlin中使用多重版式装订的正确方法



嘿,我在Recyclerview中有多个布局。我想换成视图绑定。我有多个布局和内部,在所有布局中都有相同的id,唯一的区别是位置不同。那么我该如何看待霍尔德呢。我想避开多视图支架。我试着不想使用这个多视图支架有可能这样做吗?因为viewholder中的所有代码都是相同的。感谢

AdapterClass.kt

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView

class AdapterClass(private val horizontal: Boolean = false) : RecyclerView.Adapter<AdapterViewHolder>() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AdapterViewHolder {
val inflatedView: View = if (horizontal) {
LayoutInflater.from(parent.context).inflate(R.layout.horizontal_layout, parent, false)
} else {
LayoutInflater.from(parent.context).inflate(R.layout.vertical_layout, parent, false)
}
return AdapterViewHolder(inflatedView)
}
override fun onBindViewHolder(holder: AdapterViewHolder, position: Int) {
holder.bingImage(position)
}
}
.........
}

AdapterViewHolder.kt

import android.graphics.drawable.Drawable
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
class AdapterViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bingImage(position: Int) {
with(itemView) {
val color = if (isSelected) {
itemView.context.resources.getColor(R.color.blue)
} else {
itemView.context.resources.getColor(R.color.green)
}
main_container.setBackgroundColor(color)
}
}
}

垂直.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="@+id/imageView"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

Horizontal.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/imageView"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

使用一个ViewHolder没有正确的方法可以做到这一点,最好的解决方案是为每个不同的ViewHolder创建多个ViewHolder,因为这是ViewHolder模式的核心优势。

然而,如果你坚持使用一个ViewHolder,我想出了一个解决方案,但最终,你必须分别处理每个布局绑定。

适配器

class AdapterClass(private val horizontal: Boolean = false) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (horizontal) AdapterViewHolder.fromHorizontal(parent)
else AdapterViewHolder.fromVertical(parent)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
(holder as AdapterViewHolder<*>).bingImage(position)
}
......
}

ViewHolder

class AdapterViewHolder<T : ViewBinding> private constructor(val binding: T) : RecyclerView.ViewHolder(binding.root) {
fun bingImage(position: Int) {
with(binding.root) {
val color = if (isSelected) {
context.resources.getColor(R.color.black)
} else {
context.resources.getColor(R.color.green)
}
if (binding is HorizontalBinding)
binding.mainContainer.setBackgroundColor(color)
if (binding is VerticalBinding)
binding.mainContainer.setBackgroundColor(color)
}
}
companion object {
fun fromVertical(parent: ViewGroup): AdapterViewHolder<VerticalBinding> {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = VerticalBinding.inflate(layoutInflater, parent, false)
return AdapterViewHolder(binding)
}
fun fromHorizontal(parent: ViewGroup): AdapterViewHolder<HorizontalBinding> {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = HorizontalBinding.inflate(layoutInflater, parent, false)
return AdapterViewHolder(binding)
}
}
}

但请注意,这不是一个推荐的解决方案,使用两个单独的视图持有者可以分别处理它们。


更新

如果您需要使用多个ViewHolder来实现这一点,则必须为每个布局创建一个单独的ViewHolder,并在其自己的ViewHolder内处理所有内部交互,如下所示

HorizontalViewHolder.kt

class HorizontalViewHolder private constructor(val binding: HorizontalBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(position: Int) {
with(binding.root) {
val color = if (isSelected) {
context.resources.getColor(R.color.black)
} else {
context.resources.getColor(R.color.green)
}
binding.mainContainer.setBackgroundColor(color)
}
}
companion object {
fun from(parent: ViewGroup): HorizontalViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = HorizontalBinding.inflate(layoutInflater, parent, false)
return HorizontalViewHolder(binding)
}
}
}

VerticalViewHolder.kt

class VerticalViewHolder private constructor(val binding: VerticalBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(position: Int) {
with(binding.root) {
val color = if (isSelected) {
context.resources.getColor(R.color.black)
} else {
context.resources.getColor(R.color.green)
}
binding.mainContainer.setBackgroundColor(color)
}
}
companion object {
fun from(parent: ViewGroup): VerticalViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = VerticalBinding.inflate(layoutInflater, parent, false)
return VerticalViewHolder(binding)
}
}
}

适配器类别.kt

class AdapterClass(private val horizontal: Boolean = false) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (horizontal) HorizontalViewHolder.from(parent)
else VerticalViewHolder.from(parent)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when(holder){
is HorizontalViewHolder -> holder.bind(position)
is VerticalViewHolder -> holder.bind(position)
}
}
......
}

这将使您能够灵活地在单独的ViewHolder中处理每个布局的交互。

我使用import androidx.recyclerview.widget.ListAdapter而不是RecyclerView.Adapter,因为它比它有很多优点。

我从这里学到的,Recycler View Codelab

这就是我使用RecyclerView的方式,建议使用2个不同的ViewHolder。

示例:


private val ITEM_VIEW_TYPE_HORIZONTAL = 123
private val ITEM_VIEW_TYPE_VERTICAL = 456
/**
* Custom Data Class for this adapter
*/
data class YourData(
val id: Long,
val horizontal: Boolean,
val data: Int
)
class YourAdapter(val clickListener: DataClickListener) :
ListAdapter<DataItem, RecyclerView.ViewHolder>(ListCheckDiffCallback()) {
/**
* This Function will help you out in choosing whether you want vertical or horizontal VIEW TYPE
*/
override fun getItemViewType(position: Int): Int {
return when (getItem(position).type) {
true -> ITEM_VIEW_TYPE_HORIZONTAL
false -> ITEM_VIEW_TYPE_VERTICAL
}
}
/**
* The View Type Selected above will help this function in choosing appropriate ViewHolder
*/
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ITEM_VIEW_TYPE_HORIZONTAL -> HorizontalViewHolder.from(parent)
ITEM_VIEW_TYPE_VERTICAL -> VerticalViewHolder.from(parent)
else -> throw ClassCastException("Unknown viewType $viewType")
}
}
/**
* The View Holder Created above are used here.
*/
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is HorizontalViewHolder -> {
val item = getItem(position) as DataItem.HorizontalClass
holder.bind(item.yourData, clickListener)
}
is VerticalViewHolder -> {
val item = getItem(position) as DataItem.VerticalClass
holder.bind(item.yourData, clickListener)
}
}
}
/**
* Vertical View Holder Class
*/
class VerticalViewHolder private constructor(val binding: <REPLACE_WITH_BINDING_OBJECT>) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: YourData, clickListener: DataClickListener) {
/**
* change all your view data here
* assign click listeners here
*
*  example -->
*
*  binding.xyz.setOnClickListener {
*     clickListener.onClick(item)
*  }
*/
}
companion object {
fun from(parent: ViewGroup): VerticalViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val view =  <REPLACE_WITH_BINDING_OBJECT>.inflate(R.layout.header, parent, false)
return VerticalViewHolder(binding)
}
}
}
/**
* Horizontal View Holder
*/
class HorizontalViewHolder private constructor(val binding: <REPLACE_WITH_BINDING_OBJECT>) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: YourData, clickListener: DataClickListener) {
/**
* change all your view data here
* assign click listeners here
*
*  example -->
*
*  binding.xyz.setOnClickListener {
*     clickListener.onClick(item)
*  }
*/
}
companion object {
fun from(parent: ViewGroup): HorizontalViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding =  <REPLACE_WITH_BINDING_OBJECT>.inflate(layoutInflater, parent, false)
return HorizontalViewHolder(binding)
}
}
}
}
/**
* This function checks the difference between 2 different Lists.
* 1. Old List
* 2. New List
*/
class ListCheckDiffCallback : DiffUtil.ItemCallback<DataItem>() {
override fun areItemsTheSame(oldItem: DataItem, newItem: DataItem): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: DataItem, newItem: DataItem): Boolean {
return oldItem == newItem
}
}
/**
* Interface that can be called as per your wish.
* I usually assign it inside the Fragment/Activity from where I am using the above Adapter.
* like 
*class MyFragment : Fragment(), DataClickListener
*/
interface DataClickListener {
fun onClick(data: YourData)
}
/**
* Your DataItem Class
*/
sealed class DataItem {
data class HorizontalClass(val yourData: YourData) : DataItem() {
override val id = yourData.id
override val type = true
}
data class VerticalClass(val yourData: YourData) : DataItem() {
override val id = yourData.id
override val type = false
}
abstract val id: Long
abstract val type: Boolean
}

相关内容

  • 没有找到相关文章

最新更新