如何在RecyclerView中处理临时项 实现加载指示器增删
RecyclerView临时顶部加载指示器实现方案
核心实现思路是利用多视图类型的RecyclerView.Adapter,通过状态标记控制加载项的插入与移除,比额外套头布局、加覆盖层的方案兼容性更好,不会出现布局错位、触摸事件冲突的问题。
基础配置
首先给Adapter定义两种条目类型,以及加载状态标记:
class MsgAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() { // 条目类型常量 private val TYPE_MSG = 0 private val TYPE_LOADING = 1 // 消息数据列表 private val msgList = mutableListOf<Message>() // 控制顶部加载指示器是否显示 private var isLoadingShow = false // 加载中锁,避免重复触发加载逻辑 var isLoading = false private set }
注意:IM场景的消息列表一般都会设置
layoutManager.reverseLayout = true,实现新消息沉底、向上滑动翻历史的交互,这种模式下列表视觉上的最顶部,对应Adapter里position最大的位置,不要搞反位置。
重写Adapter核心方法
1. 重写getItemCount
计算总条目数时,给加载指示器预留位置:
override fun getItemCount(): Int { return msgList.size + if (isLoadingShow) 1 else 0 }
2. 重写getItemViewType
根据位置判断当前条目类型:
override fun getItemViewType(position: Int): Int { // reverseLayout模式下,加载项放在消息列表长度对应的position,也就是视觉顶部 return if (isLoadingShow && position == msgList.size) { TYPE_LOADING } else { TYPE_MSG } }
3. 重写onCreateViewHolder和onBindViewHolder
分别加载普通消息布局、加载指示器布局即可,加载指示器布局里放居中的圆形加载控件(比如Material库的CircularProgressIndicator),高度设为48dp左右就合适,不需要绑定额外数据。
控制指示器的显示与移除
显示加载指示器
滚动监听触发历史加载逻辑时,先调用这个方法插入指示器:
fun showLoading() { if (isLoadingShow || isLoading) return isLoading = true isLoadingShow = true val insertPos = msgList.size notifyItemInserted(insertPos) // 轻微滚动到指示器位置,避免指示器被屏幕外挡住用户看不到 recyclerView.scrollToPosition(insertPos) }
移除指示器+插入新消息
历史消息加载完成(不管成功失败),先移除指示器,再处理数据:
fun loadFinish(newHistoryMsgs: List<Message> = emptyList()) { isLoading = false if (isLoadingShow) { isLoadingShow = false val removePos = msgList.size notifyItemRemoved(removePos) } // 插入新加载的历史消息,reverseLayout下历史消息追加到列表尾部即可,对应视觉顶部 if (newHistoryMsgs.isNotEmpty()) { val insertStart = msgList.size msgList.addAll(newHistoryMsgs) notifyItemRangeInserted(insertStart, newHistoryMsgs.size) // 如果需要保持用户当前浏览位置不跳动,可以提前记录RecyclerView的滚动偏移,插入后修正位置 } }
注意事项
- 滚动监听里判断到接近顶部时,先判断
isLoading标记,已经在加载中就不要重复触发请求、重复插入指示器 - 如果你的列表是正序排列(新消息在顶部,向下滑动加载更多),只需要把加载项的position改成0即可,其他逻辑一致
- 不要用给RecyclerView加外层布局、在列表顶部盖一个loading的方案,会导致滚动时布局错位、触摸事件被拦截的问题
- 加载失败时可以复用这个顶部位置,多加一种错误提示的viewType,点击重试即可,逻辑和加载指示器完全一致
内容的提问来源于stack exchange,提问作者Nikitiy
相关产品推荐
相关产品推荐

