androidkotlinandroid-recyclerviewmultiview

Multiviews using RecycleView - Kotlin(Android) - Unable to switch viewholder


I've been browsing for several days for the solution to my problem but I am stumped and could not figure out the problem. I am a relative beginner with Android/Kotlin so please bear with me.

I have a data class as per below and from a static source I populated the pid values etc.

class MyOrderList(var pid: String, var name: String, var imageUrl: String, var size: String, var description: String, val price: Int, var count: Int, var itemtotal: Int)

The idea basically is that if you iterate through the above class list, the pid is normally represented by a digit or by a specific word eg "LIQUID". So in my list, position 0 would show pid = "LIQUID", and position 1 is a digit, say pid = 2.

I wanted to create a recyclerview that when it sees LIQUID as pid on the list, it will use viewholder2 with its own layout. Otherwise it will use viewholder1 with its own layout.

The problem is that my created recyclerview only shows one viewholder. If position 0 pid is LIQUID then viewholder is ViewHolder2 even for the succeeding items on the list with PID no longer LIQUID. In short, the pid valud on position 0 would dictate the viewholder for the entire list.

I am still trying to figure out the twists and turns of RecyclerView and still do not fully understand it.

Please see below snippet.

=====================

class MyOrderCart(var myOrder: MutableList, var mymutablelist: MutableList): RecyclerView.Adapter() {

inner class ViewHolder1(itemView: View) : RecyclerView.ViewHolder(itemView) {

    fun bindView1(mycartlist: MyOrderList){
        itemView.nameView.text = mycartlist.name
        itemView.sizeView.text = "Size: ${mycartlist.size}"

        var iprice = mycartlist.price
        itemView.priceView.text = "Price: $iprice"
        var icount = mycartlist.count
        itemView.countView.text = "Count: $icount"
        var itotal = mycartlist.itemtotal
        itemView.itemtotalView.text = "Subtotal: $itotal"

        var image_checkout = itemView.findViewById(R.id.image_checkout) as ImageView
        var checkout_deletebutton = itemView.findViewById(R.id.checkout_deletebutton) as ImageButton
        var checkout_editcount = itemView.findViewById(R.id.checkout_editcount) as ImageButton
        var mytime = System.currentTimeMillis()

        try {
            Glide.with(image_checkout.getContext()).load(mycartlist.imageUrl)
                .signature(ObjectKey(mytime)).into(image_checkout)
                .clearOnDetach()
        } finally {
            image_checkout.setImageResource(R.drawable.noimage)
        }
    }
}
inner class ViewHolder2(itemView: View) : RecyclerView.ViewHolder(itemView) {
    fun bindView2(mycartlist: MyOrderList){
        itemView.checkout_inside_textview.text = mycartlist.pid
    }
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    var myorderviewtype = myOrder.get(viewType)
        return when (myorderviewtype.pid) {
            "LIQUOR" -> {
                ViewHolder2(
                    LayoutInflater.from(parent.context)
                        .inflate(R.layout.insidecheckout_label, parent, false)
                )
            }
            "NOODLES" -> {
                ViewHolder2(
                    LayoutInflater.from(parent.context)
                        .inflate(R.layout.insidecheckout_label, parent, false)
                )
            }
            else -> {
                ViewHolder1(
                    LayoutInflater.from(parent.context)
                        .inflate(R.layout.layout_insidecheckout, parent, false)
                )
            }
        }
}

override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) {
    val gsonRaw = GsonBuilder().create()
    var pos = viewHolder.getAdapterPosition()
    var mycartlist: MyOrderList = myOrder.get(position)
    when (viewHolder) {
        is ViewHolder2 -> {
            val liquorviewHolder = viewHolder as ViewHolder2
            liquorviewHolder.bindView2(mycartlist)
        }
        is ViewHolder1 -> {
            val liquorviewHolder = viewHolder as ViewHolder1
            liquorviewHolder.bindView1(mycartlist)
        }
    }

}

Solution

  • In your adapter class, you need to override the getItemViewType method. Like this:

    override fun getItemViewType(position: Int): Int {
        // return view type according to position
        // get your pid using position
        // return 0 for "LIQUOR", 1 for "NOODLES" and 2 for anything else
        // you have to return an integer value only, according to the method signature
    }
    

    Then in your onCreateViewHolder method, you use the viewType parameter, which is of type int, to inflate the required view:

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    
        return when (viewType) {
            0 -> {
                ViewHolder2(
                    LayoutInflater.from(parent.context)
                        .inflate(R.layout.insidecheckout_label, parent, false)
                )
            }
            1 -> {
                ViewHolder2(
                    LayoutInflater.from(parent.context)
                        .inflate(R.layout.insidecheckout_label, parent, false)
                )
            }
            else -> {
                ViewHolder1(
                    LayoutInflater.from(parent.context)
                        .inflate(R.layout.layout_insidecheckout, parent, false)
                )
            }
        }
    

    }