嘿,我在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
}