I'm trying to create a RecycleView of EditText that update on the spot as you add EditText with a Button.
For reference, I'd like to have something that works like a checkbox question editing on a Gform , but only with EditTexts .
Here's my code :
Main Activity Code
class AjoutObjectifActivity : AppCompatActivity() {
//ArrayList used to add items to the RecyclerView
private var etapes: ArrayList<String> = ArrayList()
private lateinit var binding: ActivityAjoutObjectifBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAjoutObjectifBinding.inflate(layoutInflater)
setContentView(binding.root)
setupButtons()
}
//The click listener of my button
private fun setupButtons() {
binding.buttonAddEtape.setOnClickListener{
addEtape()
}
}
//The function that add one element to my ArrayList, and is supposed to reload my RecyclerView to add the corresponding EditText
//I know it is supposed to erase all the EditTexts contents as well, but I'm looking to repair this after I manage to add EditTexts
private fun addEtape() {
etapes.add("")
val adapterEtapes = EtapesAdapter(etapes)
binding.recyclerViewObjectifsEtapes.adapter = adapterEtapes
}
}
My "EtapesAdapter" Code
class EtapesAdapter(private val etapes: ArrayList<String>) : RecyclerView.Adapter<EtapesAdapter.EtapeViewHolder>() {
override fun getItemCount(): Int = etapes.size
override fun onCreateViewHolder(parent: ViewGroup, position: Int): EtapeViewHolder {
val view: View = LayoutInflater.from(parent.context)
.inflate(R.layout.item_etapes_input, parent, false)
return EtapeViewHolder(view)
}
override fun onBindViewHolder(holder: EtapeViewHolder, position: Int) {
holder.bind(etapes[position])
}
class EtapeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val etape : TextView = itemView.findViewById(R.id.edit_text_etapes_objectif)
fun bind(etapes: String) = with(itemView){
etape.text = etapes
}
}
}
My Main Layout
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="@ id/recycler_view_objectifs_etapes"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</ScrollView>
My Item Layout
<EditText xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@ id/edit_text_etapes_objectif"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp" />
After a quick check of the varaibles with the debbuger, it seems that my ArrayList works perfectly and grows as you press the button, so I guess the error must be somewhere in the adapter. I tried to do it with an Array first, but since you can't add size to it, I decided to use the ArrayList instead.
Remember that I'm kind of a beginner, so maybe I use the wrong type of variables or view, in that case, feel free to tell me !
Thanks in advance
CodePudding user response:
It works better if you keep track of the 'etapes' in the adapter itself, like this.
class EtapesAdapter : RecyclerView.Adapter<EtapesAdapter.EtapeViewHolder>() {
private val etapes = ArrayList<String>()
fun addEtape(etape: String) {
this.etapes.add(etape)
notifyDataSetChanged()
}
fun addEtapes(etapes: ArrayList<String>) {
this.etapes.addAll(etapes)
notifyDataSetChanged()
}
override fun getItemCount(): Int = etapes.size
override fun onCreateViewHolder(parent: ViewGroup, position: Int): EtapeViewHolder {
val view: View = LayoutInflater.from(parent.context)
.inflate(R.layout.item_etapes_input, parent, false)
return EtapeViewHolder(view)
}
override fun onBindViewHolder(holder: EtapeViewHolder, position: Int) {
holder.bind(etapes[position])
}
class EtapeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val etape : TextView = itemView.findViewById(R.id.edit_text_etapes_objectif)
fun bind(etapes: String) = with(itemView){
etape.text = etapes
}
}
}
So now you can do this:
val adapterEtapes = EtapesAdapter()
binding.recyclerViewObjectifsEtapes.adapter = adapterEtapes
binding.recyclerViewObjectifsEtapes.layoutManager = LinearLayoutManager()
adapterEtapes.addEtapes(etapes)
and it should reload the list.
CodePudding user response:
Thanks Menno, this code sure was helpful. Your "addEtape" function reinitialised the ArrayList completly, so I replaced it by puting "etapes.add("")", instead of calling "addEtape" in mainActivity Here is the final code ;).
Main Activity
class AjoutObjectifActivity : AppCompatActivity() {
private var etapes: ArrayList<String> = ArrayList()
private lateinit var binding: ActivityAjoutObjectifBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAjoutObjectifBinding.inflate(layoutInflater)
setContentView(binding.root)
setupButtons()
}
private fun setupButtons() {
binding.buttonAddEtape.setOnClickListener{
addEtape()
}
}
private fun addEtape() {
val adapterEtapes = EtapesAdapter()
etapes.add("")
binding.recyclerViewObjectifsEtapes.adapter = adapterEtapes
binding.recyclerViewObjectifsEtapes.layoutManager =
LinearLayoutManager(this)
adapterEtapes.addEtapes(etapes)
}
}
The adapter
class EtapesAdapter : RecyclerView.Adapter<EtapesAdapter.EtapeViewHolder>() {
private val etapes = ArrayList<String>()
fun addEtapes(etapes: ArrayList<String>) {
this.etapes.addAll(etapes)
notifyDataSetChanged()
}
override fun getItemCount(): Int = etapes.size
override fun onCreateViewHolder(parent: ViewGroup, position: Int): EtapeViewHolder {
val view: View = LayoutInflater.from(parent.context)
.inflate(R.layout.item_etapes_input, parent, false)
return EtapeViewHolder(view)
}
override fun onBindViewHolder(holder: EtapeViewHolder, position: Int) {
holder.bind(etapes[position])
}
class EtapeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val etape : TextView = itemView.findViewById(R.id.edit_text_etapes_objectif)
fun bind(etapes: String) = with(itemView){
etape.text = etapes
}
}
}