在 RecyclerView 中使用多个视图类型时如何将项目添加到所需的 ViewHolder 位置?
How to add items to desired ViewHolder position when using multiple viewtypes in RecyclerView?
我画了我想要实现的东西。
解释一下函数,就是一个workout log app
.
图像表示RoutineItem
和DetailItem
都可以added and deleted
被button
.
(我没有在图片中包含添加 RoutineItem
的按钮图片!)
我创建了一个将 RoutineItem and DetailItem
添加到每个 RoutineItem
的函数,但我无法创建一个将 DetailItem
添加到最后一个 RoutineItem
的函数。
换句话说,当每个RoutineItem
的按钮被按下时,应该在每个RoutineItem
的末尾添加一个DetailItem
,但我目前的实现是任何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)
}
}
我不喜欢你处理这个的方式,因为这些东西不属于 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)
}
此方法将一个新的详细信息视图器添加到例程视图器的末尾。
您可以直接从您使用 viewmodel 的地方测试它,并在 viewholder 中使用此方法将此方法传递给 viewholder 和 viewHolder,
在你想要的 onClickListener 中设置它并传递 getAdapterPosition()
给它。
我画了我想要实现的东西。
解释一下函数,就是一个workout log app
.
图像表示RoutineItem
和DetailItem
都可以added and deleted
被button
.
(我没有在图片中包含添加 RoutineItem
的按钮图片!)
我创建了一个将 RoutineItem and DetailItem
添加到每个 RoutineItem
的函数,但我无法创建一个将 DetailItem
添加到最后一个 RoutineItem
的函数。
换句话说,当每个RoutineItem
的按钮被按下时,应该在每个RoutineItem
的末尾添加一个DetailItem
,但我目前的实现是任何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)
}
}
我不喜欢你处理这个的方式,因为这些东西不属于 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)
}
此方法将一个新的详细信息视图器添加到例程视图器的末尾。
您可以直接从您使用 viewmodel 的地方测试它,并在 viewholder 中使用此方法将此方法传递给 viewholder 和 viewHolder,
在你想要的 onClickListener 中设置它并传递 getAdapterPosition()
给它。