RecyclerView滚动后ImageView位置错乱问题(使用Picasso)
解决RecyclerView+Picasso图片加载时视图错乱的问题
嘿,这个问题我之前做聊天界面的时候也踩过坑!核心问题就是RecyclerView的ViewHolder复用机制导致的视图状态残留,加上你在onBindViewHolder里没有完整重置所有视图的状态,才出现了滚动时图片位置错乱、文本消息被覆盖的情况。另外那个Logcat的错误日志和你的问题无关,先不用管它。
问题分析
你的代码里存在两个关键问题:
- 视图状态没有完全重置:当处理图片消息时,你只设置了对应ImageView和CardView可见,但在处理文本消息时,没有把图片相关的视图(
imageMessageOut、cardViewOut等)设置为隐藏。当RecyclerView复用之前显示图片的ViewHolder来显示文本时,旧的图片视图会残留显示,导致错乱。 - Picasso加载请求未取消:ViewHolder被滚动出屏幕后,之前的图片加载请求可能还在后台运行,当请求完成时,图片会被加载到已经被复用的ViewHolder上,导致错误位置显示图片。
修复方案
修改你的onBindViewHolder方法,确保每次绑定都先重置所有视图状态,同时优化Picasso的加载逻辑:
override fun onBindViewHolder(holder: ViewHolder, position: Int) { val chat: Chat = mChatList[position] // 第一步:强制重置所有视图的可见性,彻底避免复用残留 holder.textMessage?.visibility = View.GONE holder.imageMessageOut?.visibility = View.GONE holder.cardViewOut?.visibility = View.GONE holder.imageMessageIn?.visibility = View.GONE holder.cardViewIn?.visibility = View.GONE // 处理图片消息 if (chat.getMessage() == "IMAGE" && chat.getUrl().isNotEmpty()) { if (chat.getSender() == currentUserID) { // 显示发送方图片视图 holder.imageMessageOut?.visibility = View.VISIBLE holder.cardViewOut?.visibility = View.VISIBLE // 取消该ImageView上的旧请求,防止加载到错误位置 Picasso.get().cancelRequest(holder.imageMessageOut) // 加载图片,可按需添加占位图提升体验 Picasso.get().load(chat.getUrl()) // .placeholder(R.drawable.default_image) .into(holder.imageMessageOut) } else { // 显示接收方图片视图 holder.imageMessageIn?.visibility = View.VISIBLE holder.cardViewIn?.visibility = View.VISIBLE Picasso.get().cancelRequest(holder.imageMessageIn) Picasso.get().load(chat.getUrl()) // .placeholder(R.drawable.default_image) .into(holder.imageMessageIn) } } // 处理文本消息 else { // 显示文本视图并设置内容 holder.textMessage?.visibility = View.VISIBLE holder.textMessage?.text = chat.getMessage() } }
额外说明
- 关于Logcat的
E/UIFirst: failed to open /proc/31416/stuck_info错误:这是系统层面的调试日志,和你的应用逻辑完全无关,不会影响功能,可以直接忽略。 - 如果你的ViewHolder里还存在其他视图(比如时间、状态图标等),也要在开头的重置步骤里统一处理它们的状态,避免类似的复用问题。
内容的提问来源于stack exchange,提问作者Stackoverflower
相关产品推荐
相关产品推荐

