1

I currently have a fully functioning expandable RecyclerView (with two distinct views: one for the header and the other for the contents of each header). The contents of each card under a header is retrieved from an API call to my back end.

Today, I managed to implement swipe to refresh functionality but the issue is that when I do the refresh, the groups all collapse. From a UI/UX perspective, this isn't very appealing and adds extra steps for the user. As such, what I'm looking for is a way to perform the swipe to refresh without causing the groups to collapse (i.e. the contents of the card get updated but the cards remain at the same position as when the refresh is called). I've looked at using onSaveInstanceState and onRestoreInstanceState as detailed in this answer here and here but to no avail.

My code for the adapter is as follows:

class BusStopsServicesArrivalRVAdapter :
    RecyclerView.Adapter<RecyclerView.ViewHolder>(), BusStopNoSectionHeaderViewHolder.HeaderViewHolderCallback {
    private val SERVICE_TYPE = 1
    private val STOP_TYPE = 2
    private var busStopServiceList: ArrayList<BusStopService>? = null
    private var busStopList: ArrayList<String>? = null

    private var busArrivalViewTypes: SparseArray<BusArrivalViewType>? = null
    private var headerExpandTracker: SparseIntArray? = null

    lateinit var context: Context

    var nineOneCount = 0
    var threeOneCount = 0
    var threeNineCount = 0
    var fiveNineCount = 0

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val view: View
        when (viewType) {
            SERVICE_TYPE -> {
                view = LayoutInflater.from(parent.context)
                    .inflate(R.layout.card_bus_stop_service, parent, false)
                return BusStopServiceHolder(view)
            }
            STOP_TYPE -> {
                view = LayoutInflater.from(parent.context)
                    .inflate(R.layout.card_bus_stop_section, parent, false)
                return BusStopNoSectionHeaderViewHolder(view, this)
            }
            else -> {
                view = LayoutInflater.from(parent.context)
                    .inflate(R.layout.card_bus_stop_service, parent, false)
                return BusStopServiceHolder(view)
            }
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val itemViewType = getItemViewType(position)
        val viewType = busArrivalViewTypes!!.get(position)
        if (itemViewType == SERVICE_TYPE) {
            bindBusStopServiceViewHolder(holder, viewType)
        } else {
            bindHeaderViewHolder(holder, position, viewType)
        }
    }

    private fun bindHeaderViewHolder(holder: RecyclerView.ViewHolder, position: Int, busArrivalViewType: BusArrivalViewType) {
        val dataIndex = busArrivalViewType.dataIndex
        val headerViewHolder = holder as BusStopNoSectionHeaderViewHolder
        when(busStopList!![dataIndex]) {
            "D" -> {
                headerViewHolder.busStopNoTextView.text =
                    context.resources.getString(R.string.bus_stop_services_description_D)
            }

            "C" -> {
                headerViewHolder.busStopNoTextView.text =
                    context.resources.getString(R.string.bus_stop_services_description_C)
            }

            "B" -> {
                headerViewHolder.busStopNoTextView.text =
                    context.resources.getString(R.string.bus_stop_services_description_B)
            }

            "A" -> {
                headerViewHolder.busStopNoTextView.text =
                    context.resources.getString(R.string.bus_stop_services_description_A)
            }
        }
        // headerViewHolder.busStopNoTextView.text = busStopList!![dataIndex]
        if (isExpanded(position)) {
            headerViewHolder.busStopNoTextView
                .setCompoundDrawablesWithIntrinsicBounds(null, null, headerViewHolder.arrowUp, null)
        } else {
            headerViewHolder.busStopNoTextView
                .setCompoundDrawablesWithIntrinsicBounds(null, null, headerViewHolder.arrowDown, null)
        }
    }

    private fun bindBusStopServiceViewHolder(holder: RecyclerView.ViewHolder, busArrivalViewType: BusArrivalViewType) {
        val dataIndex = busArrivalViewType.dataIndex
        (holder as BusStopServiceHolder).bindData(busStopServiceList!![dataIndex], context)
    }

    override fun getItemCount(): Int {
        var count = 0
        if (busStopList != null && busStopServiceList != null) {
            busArrivalViewTypes!!.clear()
            var collapsedCount = 0
            for (i in busStopList!!.indices) {
                busArrivalViewTypes!!.put(count, BusArrivalViewType(i, STOP_TYPE))
                count += 1
                val userType = busStopList!![i]
                val childCount = getChildCount(userType)
                if (headerExpandTracker!!.get(i) != 0) {
                    // Expanded State
                    for (j in 0 until childCount) {
                        busArrivalViewTypes!!.put(count, BusArrivalViewType(count - (i + 1) + collapsedCount, SERVICE_TYPE))
                        count += 1
                    }
                } else {
                    // Collapsed
                    collapsedCount += childCount
                }
            }
        }
        return count
    }

    override fun getItemViewType(position: Int): Int {
        return if (busArrivalViewTypes!!.get(position).type === STOP_TYPE) {
            STOP_TYPE
        } else {
            SERVICE_TYPE
        }
    }

    private fun getChildCount(type: String): Int {
        when (type) {
            "D" -> return nineOneCount
            "C" -> return threeOneCount
            "B" -> return threeNineCount
            "A" -> return fiveNineCount
            else -> return 0
        }
    }

    fun setUserListAndType(busStopServiceList: ArrayList<BusStopService>?, busStopNoList: ArrayList<String>?, c: Context) {
        if (busStopServiceList != null && busStopNoList != null) {
            this.busStopServiceList = busStopServiceList
            this.busStopList = busStopNoList
            this.context = c
            busArrivalViewTypes = SparseArray<BusArrivalViewType>(busStopServiceList.size + busStopNoList.size)
            headerExpandTracker = SparseIntArray(busStopNoList.size)
            notifyDataSetChanged()

            for (i in busStopServiceList.indices) {
                when(busStopServiceList[i].busStopCode) {
                    "D" -> {
                        nineOneCount += 1
                    }

                    "C" -> {
                        threeOneCount += 1
                    }

                    "B" -> {
                        threeNineCount += 1
                    }

                    "A" -> {
                        fiveNineCount += 1
                    }
                }
            }


        }
    }

    override fun onHeaderClick(position: Int) {
        val viewType = busArrivalViewTypes!!.get(position)
        val dataIndex = viewType.dataIndex
        val userType = busStopList!![dataIndex]
        val childCount = getChildCount(userType)
        if (headerExpandTracker!!.get(dataIndex) == 0) {
            headerExpandTracker!!.put(dataIndex, 1)
            notifyItemRangeInserted(position + 1, childCount)
        } else {
            headerExpandTracker!!.put(dataIndex, 0)
            notifyItemRangeRemoved(position + 1, childCount)
        }
    }

    override fun isExpanded(position: Int): Boolean {
        val dataIndex = busArrivalViewTypes!!.get(position).dataIndex
        return headerExpandTracker!!.get(dataIndex) == 1
    }

}
piet.t
  • 11,718
  • 21
  • 43
  • 52
pratty
  • 33
  • 7

0 Answers0