So, the problem statement is I want to implement a feature in which user can add and remove as many items in the list as they want. I thought of using RecyclerView with edittext in each view and handling the state of all Views and saving the data as the data state changes.
So far I have tried this in the CheckListAdapter:
import android.text.Editable
import android.view.LayoutInflater
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import androidx.core.widget.addTextChangedListener
import androidx.recyclerview.widget.RecyclerView
import com.app.dynamicrv.databinding.CheckListItemBinding
class CheckListAdapter
: RecyclerView.Adapter<CheckListAdapter.ViewHolder>() {
private val checkListItems = arrayListOf("")
inner class ViewHolder(val binding: CheckListItemBinding) :
RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
CheckListItemBinding.inflate(
LayoutInflater.from(parent.context),
parent, false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val index = checkListItems[position]
holder.binding.checkListEt.setText(index)
holder.binding.checkListEt.addTextChangedListener {text: Editable? ->
if ( position < checkListItems.size)
checkListItems[position] = text.toString()
}
holder.binding.checkListEt.setOnEditorActionListener { v, actionId, event ->
if (actionId == EditorInfo.IME_ACTION_DONE){
checkListItems.add("")
holder.binding.checkListEt.setSelection(0)
notifyItemInserted(checkListItems.size)
}
true
}
}
override fun getItemCount() = checkListItems.size
fun getListItems() : List<String>{
return checkListItems
}
}
The result I was expecting that user can enter another field in the recyclerView by actionDone. But It doesn't work as expected.
I tried a lot of approaches, but this one is best among them along with error handling. But still you can enhance if you think there is something that can be improved.
My CheckListAdapter.kt looks like this:
package com.app.dynamicrv.adapters
import android.content.Context
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import android.widget.Toast
import androidx.core.widget.addTextChangedListener
import androidx.recyclerview.widget.RecyclerView
import com.app.dynamicrv.R
import com.app.dynamicrv.databinding.CheckListItemBinding
class CheckListAdapter
(private val context : Context,
private val recyclerView: RecyclerView )
: RecyclerView.Adapter<CheckListAdapter.ViewHolder>() {
private val checkListItems = arrayListOf("")
inner class ViewHolder(val binding: CheckListItemBinding) :
RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
CheckListItemBinding.inflate(
LayoutInflater.from(parent.context),
parent, false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val index = checkListItems[position]
holder.binding.checkListEt.setText(index)
val pos = holder.adapterPosition
// Add TextWatcher for EditText changes
holder.binding.checkListEt.addTextChangedListener { text: Editable? ->
if (position < checkListItems.size)
checkListItems[position] = text.toString()
}
// Ensure focus and cursor position for the last item
if (pos == checkListItems.size - 1) {
holder.binding.checkListEt.requestFocus()
holder.binding.checkListEt.setSelection(holder.binding.checkListEt.text.length) // Move cursor to end
}
// Handle IME_ACTION_DONE to add a new item
holder.binding.checkListEt.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
if (checkListItems.size > 0) {
checkListItems.add("") // Add new empty item
notifyItemInserted(checkListItems.size - 1)
// Scroll to the newly added item
holder.itemView.post {
recyclerView.scrollToPosition(checkListItems.size - 1)
}
}
true
} else {
false
}
}
// Handle item deletion
holder.binding.deleteItem.setOnClickListener {
if (checkListItems.size > 1 && pos in checkListItems.indices) {
checkListItems.removeAt(pos)
notifyItemRemoved(pos)
notifyItemRangeChanged(pos, checkListItems.size)
// Optionally, focus and scroll to the previous item or the new last item
if (pos < checkListItems.size) {
holder.itemView.post {
recyclerView.scrollToPosition(pos)
if (checkListItems.size > 0) {
recyclerView.findViewHolderForAdapterPosition(pos)?.itemView?.findViewById<EditText>(
R.id.checkListEt)?.requestFocus()
}
}
}
} else {
Toast.makeText(context, "Must have at least 1 item", Toast.LENGTH_SHORT).show()
}
}
}
override fun getItemCount() = checkListItems.size
fun getListItems() : List<String>{
return checkListItems
}
}