Home > Mobile >  Dynamic and unlimited RecycleView of EditText
Dynamic and unlimited RecycleView of EditText

Time:01-21

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
        }
    }


}
  • Related