You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 20:48:18