Сохранение расширяемого макета повторного просмотра при извлечении и обновлении данных из API - PullRequest
1 голос
/ 17 июня 2019

В настоящее время у меня есть полностью работоспособное расширяемое RecyclerView (с двумя различными представлениями: одно для заголовка и другое для содержимого каждого заголовка). Содержимое каждой карточки под заголовком извлекается из вызова API моего бэкенда.

Сегодня мне удалось внедрить функцию свайпа для обновления, но проблема в том, что когда я делаю обновление, все группы разрушаются. С точки зрения UI / UX, это не очень привлекательно и добавляет дополнительные шаги для пользователя. Таким образом, я ищу способ выполнить свайп для обновления без разрушения групп (то есть содержимое карты обновляется, но карты остаются в том же положении, что и при вызове обновления). Я рассмотрел использование onSaveInstanceState и onRestoreInstanceState, как подробно описано в этом ответе здесь и здесь , но безрезультатно.

Мой код для адаптера выглядит следующим образом:

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
    }

}
...