在 RecyclerView 中使用多个视图类型时如何将项目添加到所需的 ViewHolder 位置?
Posted
技术标签:
【中文标题】在 RecyclerView 中使用多个视图类型时如何将项目添加到所需的 ViewHolder 位置?【英文标题】:How to add items to desired ViewHolder position when using multiple viewtypes in RecyclerView? 【发布时间】:2021-11-22 15:58:22 【问题描述】:我画了我想要实现的东西。
解释一下函数,就是workout log app
。
图像意味着RoutineItem
和DetailItem
都可以是added and deleted
by button
。
(我没有包含在图片中添加RoutineItem
的按钮图片!)
我创建了一个同时添加RoutineItem and DetailItem
的函数,但我无法创建一个函数将DetailItem
添加到最后一个RoutineItem
。
也就是说,当每个RoutineItem
的按钮被按下时,一个DetailItem
应该被添加到每个RoutineItem
的末尾,但是我目前的实现是任何RoutineItem
按钮总是被添加到按下按钮时List
的结尾。
我不确定如何找出每个 RoutineItem
的结尾,因为我正在使用 Multiple ViewHolder
来实现它。
我如何知道每个RoutineItem
后面列出的最后一个DetailItem
?
RoutineItem.kt
sealed class RoutineItem()
data class RoutineModel(
val workout: String, // excercise
val unit: String, // unit (kg or lbs)
var routineDetail: List<DetailModel> = listOf()
) : RoutineItem()
data class DetailModel(
val set: String,
val reps: String = "1",
val weight: String
) : RoutineItem()
ViewHolder.kt
sealed class RoutineItemViewHolder(binding: ViewBinding) : RecyclerView.ViewHolder(binding.root)
class RoutineViewHolder(
private val binding: ItemRoutineBinding,
private val addDetailClicked: (Int) -> Unit,
val deleteDetailClicked: (Int) -> Unit
)
: RoutineItemViewHolder(binding)
init
binding.add.setOnClickListener
addDetailClicked(adapterPosition)
fun bind(item : RoutineItem.RoutineModel)
binding.workout.text = item.workout
class RoutineDetailViewHolder(private val binding: ItemRoutineDetailBinding)
: RoutineItemViewHolder(binding)
fun bind()
// EMPTY
适配器
class RoutineItemAdapter(
private val addDetailClicked: (Int) -> Unit,
private val deleteDetailClicked: (Int) -> Unit) :
ListAdapter<RoutineItem, RoutineItemViewHolder>(RoutineDiffCallback2())
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RoutineItemViewHolder
return when(viewType)
R.layout.item_routine -> RoutineItemViewHolder.RoutineViewHolder(
ItemRoutineBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
),
addDetailClicked,
deleteDetailClicked
)
R.layout.item_routine_detail -> RoutineItemViewHolder.RoutineDetailViewHolder(
ItemRoutineDetailBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
else -> throw IllegalArgumentException("Invalid ViewType Provided")
override fun onBindViewHolder(holder: RoutineItemViewHolder, position: Int)
when(holder)
is RoutineItemViewHolder.RoutineViewHolder -> holder.bind(currentList[position] as RoutineItem.RoutineModel)
is RoutineItemViewHolder.RoutineDetailViewHolder -> holder.bind()
override fun getItemCount(): Int = currentList.size // footer 때문에 +1
override fun getItemViewType(position: Int): Int
return when(currentList[position])
is RoutineItem.RoutineModel -> R.layout.item_routine
is RoutineItem.DetailModel -> R.layout.item_routine_detail
else -> throw IllegalArgumentException("Invalid ViewType Provided")
ViewModel
class WriteRoutineViewModel : ViewModel()
private var _items: MutableLiveData<List<RoutineItem>> = MutableLiveData(listOf())
private val routines = mutableListOf<RoutineItem>()
val items: LiveData<List<RoutineItem>> = _items
fun addRoutine(workout: String)
routines.add(RoutineItem.RoutineModel(workout, "TEST"))
routines.add(RoutineItem.DetailModel("1","3","3"))
_items.postValue(routines)
fun addDetail(pos: Int)
routines.add(RoutineItem.DetailModel("1","3","3"))
_items.postValue(routines)
【问题讨论】:
试试环氧树脂。 (github.com/airbnb/epoxy) 使用方法 -> proandroiddev.com/… 【参考方案1】:我不喜欢你处理这个的方式,因为这些东西不属于ViewModel
,它们属于Adapter
,但是在你的代码中,你可以在你的ViewModel
中添加这个函数来实现你想要什么这个方法得到RoutineViewHolder
的位置并在它的末尾添加一个DetailViewHolder
:
fun addDetailItemToEndOfRoutine(parentRoutineViewHolderPosition : Int)
var addingPosition:Int = parentRoutineViewHolderPosition
for(position in (parentRoutineViewHolderPosition + 1) .. routines.size())
if(routines.getOrNull(position) is RoutineItem.DetailModel)
continue
addingPosition = position - 1
break
//now you have found the position and you can add the detail model you want
items.add(addingPosition + 1, RoutineItem.DetailModel("1","3","3"))
_items.postValue(routines)
此方法将一个新的细节视图添加到常规视图的末尾。
您可以直接从使用视图模型的位置对其进行测试,并在视图支架中使用此方法将此方法传递给视图支架和视图支架,
在你想要的 onClickListener 中设置它并将getAdapterPosition()
传递给它。
【讨论】:
以上是关于在 RecyclerView 中使用多个视图类型时如何将项目添加到所需的 ViewHolder 位置?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Firebase 中将多个 Recyclerview 设置为单个适配器(多视图类型)?