I drew what I'm trying to implement.
To explain the function, it is a workout log app
.
Image means that both RoutineItem
and DetailItem
can be added and deleted
by button
.
(I didn't include a picture of a button that adds a RoutineItem
in the image!)
I made a function that adds both RoutineItem and DetailItem
, but I couldn't create a function that adds DetailItem
to each RoutineItem
last.
In other words, when the button of each RoutineItem
is pressed, a DetailItem
should be added to the end of each RoutineItem
, but my current implementation is that any RoutineItem
button is always added to the end of the List
when the button is pressed.
I'm not sure how to figure out the end of each RoutineItem
because I'm implementing it using Multiple ViewHolder
.
How do I know the last DetailItem
listed after each RoutineItem
?
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
}
}
}
Adapter
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)
}
}
CodePudding user response:
I don't like the way you have handled this because these things do not belong to ViewModel
and they belong to the Adapter
, but in your code, you can add this function to your ViewModel
to achieve what you want this method get the position of RoutineViewHolder
and add a DetailViewHolder
to end of it:
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)
}
this method adds a new detail veiwholder to the end of the Routine viewholder.
you can test it directly from where you use your viewmodel and for using this method in viewholder pass this method to viewholder and in viewHolder,
set it in the onClickListener you want and pass getAdapterPosition()
to it.