good112233
good112233

Reputation: 138

Multiple list type in recyclerview

i have dynamic list question from API with recyclerview but every question have different type (Input Text,Radio Button,etc) so i need make list with diferent type in my recyclerview. i seacrh on internet also in this site i need to check list type in onCreateViewHolder and return view with different layout source but i still cant solve my problem,my result not return any error but my list is always return just first type view (input_field layout) but canot return second type view (input_selection layout)

this my adapter

class QuestionViewAdapter(private val listQuestion: ArrayList<Question>) : RecyclerView.Adapter<QuestionViewAdapter.InputField>() {
    private var context: Context? = null
    override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): InputField {
        context = viewGroup.context
        if(listQuestion[i].prodeskel_type_id == 1){
            var view = LayoutInflater.from(viewGroup.context).inflate(R.layout.input_field, viewGroup, false)
            return InputField(view)
        } else {
            var view = LayoutInflater.from(viewGroup.context).inflate(R.layout.input_selection, viewGroup, false)
            return InputField(view)
        }
    }

    override fun onBindViewHolder(InputFieldHolder: InputField, i: Int) {
        val question = listQuestion.get(i)

        if(question.prodeskel_type_id == 2){
            InputFieldHolder.questionText?.text = question.isi
            var rprms = InputFieldHolder.radiogroup?.layoutParams
            for (i in question.pilihan_jawabans) {
                val rdbtn = RadioButton(context)
                rdbtn.id = View.generateViewId()
                rdbtn.text = i.isi.toString()
                rprms = RadioGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
                InputFieldHolder.radiogroup?.addView(rdbtn, rprms)

            }
        } else {
            InputFieldHolder.txtInput?.hint = question.isi
            if(question.getEditTextValue().toString() != "null"){
                InputFieldHolder.txtInput?.editText?.setText(question.getEditTextValue().toString())
            }


            InputFieldHolder.txtInput?.editText?.addTextChangedListener(object : TextWatcher {

                override fun afterTextChanged(s: Editable) {
                    InputFieldHolder.txtInput?.editText?.text?.length?.let {
                        InputFieldHolder.txtInput?.editText?.setSelection(
                            it
                        )
                    }
                }

                override fun beforeTextChanged(s: CharSequence, start: Int,
                                               count: Int, after: Int) {

                }

                override fun onTextChanged(s: CharSequence, start: Int,
                                           before: Int, count: Int) {
                    Log.i("Edit", InputFieldHolder.txtInput?.editText?.text.toString())
                    question.setEditTextValue(InputFieldHolder.txtInput?.editText?.text.toString())
                }
            })
        }
        InputFieldHolder.setIsRecyclable(false);
    }

    override fun getItemCount(): Int {
        return listQuestion.size
    }

    public fun getItem(): ArrayList<Question> {
        return listQuestion
    }

    inner class InputField internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView) {
        internal var txtInput: TextInputLayout? = null
        internal var radiogroup: RadioGroup? = null
        internal var questionText: TextView? = null

        init {
            txtInput = itemView.findViewById(R.id.txtInputField)
            radiogroup = itemView.findViewById(R.id.radiogroup)
            questionText = itemView.findViewById(R.id.questionText)
        }
     }
}

UPDATE (SOLVED)

i solved by add this function

override fun getItemViewType(position: Int) = listQuestion[position].prodeskel_type_id

and add selection condition on onCreateViewHolder and onBindViewHolder

override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): InputField {

    if(viewType == 1){
        //view type layout1
    } else {
        //view type layout2

    }
}


override fun onBindViewHolder(InputFieldHolder: InputField, i: Int) {

    if(getItemViewType(i) == 1){
        //add text to layout1

    } else {
        //add text to layout2
    }

}

Upvotes: 0

Views: 172

Answers (2)

droidev
droidev

Reputation: 7380

As you have written in the code onCreateViewHolder receives an Int and which is the type of view. based on that it creates viewholders.

But in your case the view type will be always 0. onCreateViewHolder receives viewType and which is returned by getItemViewType which you need to override.

for example

    @Override
    public int getItemViewType(int position) {
        // Just as an example, return 0 or 2 depending on position
        // Note that unlike in ListView adapters, types don't have to be contiguous
        return viewType;
    }

also your onCreateViewHolder and onBindViewHolder should be depending on the viewType received as argument.

example

override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): InputField {       
 if(viewType == 1){  
  ... 
 }
}

override fun onBindViewHolder(InputFieldHolder: InputField, position: Int) {
  if(getViewType(position) == 1){ 
     ... 
  }
}

In your scenario getViewType will be something like this

override fun getItemViewType(position: Int) = listQuestion[position].prodeskel_type_id

Hope that helps. also I would ask you to understand how RecyclerView and its adapter works

Upvotes: 1

Ircover
Ircover

Reputation: 2446

To use multiple item types in RecyclerView you need to override method getItemViewType. The value it returns will be placed as 2-nd parameter in onCreateViewHolder method (BTW, better to rename it from i to viewType). Default implementation of getItemViewType always returns same value, so you would never get what you want with it.

Upvotes: 1

Related Questions