android - 在从 API 检索和更新数据时保留可扩展 recyclerview 的布局
问题描述
我目前有一个功能齐全的可扩展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
}
}
解决方案
推荐阅读
- python - 如何使用 Flask 将函数的结果返回到网页
- python - 在更大的阵列上训练时的损失变为 inf 然后变为 nan(Tensorflow)
- string - 在 vuejs 中只使字符串的一部分变为粗体
- php - 页面刷新后会话被破坏
- javascript - Bot 不会编辑每个频道的角色权限
- html - 如何使用 *ngFor 从对象角度获取值?
- android - FloatingActionButton 立即隐藏
- javascript - 如何在 javascript/jquery 中暂停音频?
- flutter - 如何在本地存储数据并在 FLUTTER 的输入编辑字段中显示和编辑?
- rust - 如何使用组合器(for_each 除外)在 Rust 中运行流以完成并且没有 while 循环?