在 RecyclerView 中使用多个视图类型时如何将项目添加到所需的 ViewHolder 位置?

How to add items to desired ViewHolder position when using multiple viewtypes in RecyclerView?

我画了我想要实现的东西。

解释一下函数,就是一个workout log app.

图像表示RoutineItemDetailItem都可以added and deletedbutton.

(我没有在图片中包含添加 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() 给它。