滚动时的回收范围弄乱视图 - 带有图片
我正在使用聊天应用程序。我有聊天活动,两个用户可以在其中发送诸如WhatsApp之类的消息,但是我有问题。
就像您可以在图片中看到的那样( https://ibb.co/3cyyx01 ),视图在滚动时,我想我知道为什么。
研究这些帖子之后: recyClerView在滚动时会弄乱, =“ https://stackoverflow.com/questions/29702357/android-recyclerview-content-content-messed-messed-up-after-scrolling/34217561#34217561”
OnBindViewHolder ,因为我在某些视图上使用可见性选项(view.gone and view.ible.ible),我认为这些视图正在与此视图相关。可见性错误。
此外,我在 holder.setisrecyclable(false)
in onBindViewHolder
中使用了,以便检查是否是导致问题的回收部分,当我使用问题时,它可以很好地工作。
这是循环系统适配器:
private const val SEND_LAYOUT = 0
private const val RECEIVED_LAYOUT = 1
class ChatRecyclerViewAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private lateinit var receiverUserPic: String
private lateinit var messageList: List<Message>
private lateinit var currentUserPic: String
private lateinit var currentUserUID: String
private lateinit var targetUID: String
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val viewHolder: RecyclerView.ViewHolder
val view: View
viewHolder = if (viewType == SEND_LAYOUT) {
view = LayoutInflater.from(parent.context)
.inflate(R.layout.sent_message_row, parent, false)
SentViewHolder(view)
} else {
view = LayoutInflater.from(parent.context)
.inflate(R.layout.recieved_message_row, parent, false)
ReceivedViewHolder(view)
}
return viewHolder
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
//holder.setIsRecyclable(false)
val currentMessage = messageList[position]
if (holder.itemViewType == SEND_LAYOUT) {
holder as SentViewHolder
holder.bindSentRow(currentMessage)
} else {
holder as ReceivedViewHolder
holder.bindReceivedRow(currentMessage)
}
}
override fun getItemCount(): Int {
return messageList.size
}
override fun getItemViewType(position: Int): Int {
val currentMessage = messageList[position]
return if (FirebaseAuth.getInstance().currentUser?.uid.equals(currentMessage.sender))
SEND_LAYOUT
else
RECEIVED_LAYOUT
}
inner class SentViewHolder(private val itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindSentRow(message: Message) {
val sentMessageTextView =
itemView.findViewById<TextView>(R.id.sentMessage)
val sentImage = itemView.findViewById<ImageView>(R.id.sentImage)
val profileImage =
itemView.findViewById<ImageView>(R.id.sentMessageProfilePicture)
val sentIsSeenImageTextView =
itemView.findViewById<TextView>(R.id.sentIsSeenImageTextView)
val sentIsSeenTextView =
itemView.findViewById<TextView>(R.id.sentIsSeenTextView)
profileImage.setOnClickListener {
val visitProfileIntent = Intent(it.context, VisitProfileActivity::class.java)
visitProfileIntent.putExtra("targetUID", currentUserUID)
it.context.startActivity(visitProfileIntent)
}
if (message.message.equals("Sent you an image") && !message.url.equals("")) {
sentMessageTextView.visibility = View.GONE
sentIsSeenImageTextView.visibility = View.VISIBLE
sentIsSeenTextView.visibility = View.GONE
sentImage.visibility = View.VISIBLE
Glide.with(itemView.rootView).load(message.url)
.override(SIZE_ORIGINAL, SIZE_ORIGINAL)
.error(R.drawable.error_icon)
.placeholder(R.drawable.loading_icon)
.listener(object : RequestListener<Drawable?> {
override fun onLoadFailed(
@Nullable e: GlideException?,
model: Any,
target: Target<Drawable?>,
isFirstResource: Boolean
): Boolean {
return false
}
override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: Target<Drawable?>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
return false
}
}).into(sentImage)
if (adapterPosition == messageList.size - 1) {
sentIsSeenImageTextView.visibility = View.VISIBLE
sentIsSeenTextView.visibility = View.GONE
if (message.seen == true) {
sentIsSeenImageTextView.text = "Seen"
} else {
sentIsSeenImageTextView.text = "Sent"
}
} else {
sentIsSeenImageTextView.visibility = View.GONE
}
} else {
sentMessageTextView.visibility = View.VISIBLE
sentMessageTextView.text = message.message
sentIsSeenImageTextView.visibility = View.GONE
if (adapterPosition == messageList.size - 1) {
sentIsSeenTextView.visibility = View.VISIBLE
sentIsSeenImageTextView.visibility = View.GONE
if (message.seen == true) {
sentIsSeenTextView.text = "Seen"
} else {
sentIsSeenTextView.text = "Sent"
}
}
}
Glide.with(itemView.rootView).load(currentUserPic).into(profileImage)
}
}
inner class ReceivedViewHolder(private val itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindReceivedRow(message: Message) {
val receiveMessageTextView =
itemView.findViewById<TextView>(R.id.receivedMessage)
val receiveImage =
itemView.findViewById<ImageView>(R.id.receivedImage)
val receiveProfileImage =
itemView.findViewById<ImageView>(R.id.receivedMessageProfileImage)
receiveProfileImage.setOnClickListener {
val visitProfileIntent = Intent(it.context, VisitProfileActivity::class.java)
visitProfileIntent.putExtra("targetUID", targetUID)
it.context.startActivity(visitProfileIntent)
}
if (message.message.equals("Sent you an image") && !message.url.equals("")) {
receiveMessageTextView.visibility = View.GONE
receiveImage.visibility = View.VISIBLE
Glide.with(itemView.rootView).load(message.url).into(receiveImage)
} else {
receiveMessageTextView.visibility = View.VISIBLE
receiveMessageTextView.text = message.message
}
Glide.with(itemView.rootView).load(receiverUserPic).into(receiveProfileImage)
}
}
fun getMessageList(): List<Message> {
return messageList
}
fun setMessagesList(
newList: List<Message>,
userProfilePic: String,
userProfilePic1: String,
currentUID: String,
receiverUID: String
) {
messageList = newList
currentUserPic = userProfilePic
receiverUserPic = userProfilePic1
currentUserUID = currentUID
targetUID = receiverUID
notifyDataSetChanged()
}
}
pastebin链接: https://pastebin.com/ri5puadk
谢谢!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
recyLeview
的工作是基于 recycles 的视图以显示列表。当您滚动时,视图
从屏幕上出来的不会被破坏,但再次被重复使用以显示新列表项目。因此,如果您更改可见性
或视图的任何其他属性,并且不要在onBindViewHolder
中再次重置它,则它将显示所有属性被回收了。在上面的方法中,我们隐藏
textView
当文本为空
时,我们没有在else> else
条件中设置任何内容。因此,当视图
为此,我们将可见性被回收时,他们永远不会显示textView
,因为它正在重复使用查看
。为了解决这个问题,我们必须为true
和false
条件设置视图的属性。在
sentViewHolder
和readeviewholder
中,您将ImageView
的可见性设置为可见>可见
,但您永远不会将其设置为
走了
。在
的其他条件下(Message.Message.Equals(“发送给您的映像”)
的代码> ImageView
togone
。也为所有其他视图做同样的事情,因此您不会得到意外的UI。Working of the
recyleView
is based on that, it recycles views to show a list. When you scroll,views
which go out of the screen, are not destroyed but are reused again to show the new list item. So, if you changevisibility
or any other property of a view and don't reset it again insideonBindViewHolder
, then it would show all the properties which were set earlier before it got recycled.In the above method, we are hiding
textView
when text isempty
, but we are not setting anything in theelse
condition. So whenviews
, for which we've set visibility togone
would be recycled, they'd never show thetextView
as it is reusing theview
. To deal with this, we've to set the properties of the views fortrue
andfalse
conditions each.In
SentViewHolder
andReceivedViewHolder
, you are setting the visibility of theImageView
tovisible
but you are never setting it to
gone
.In the else condition of
(message.message.equals("Sent you an image") && !message.url.equals(""))
, set thevisibility
ofImageView
toGONE
. Do the same for all other views too, so you don't get an unexpected UI.因为视图持有人被回收并重复使用,这会导致您的观点处于错误状态。
在
sendviewholder
类中,您仅通过设置可见的可见性来处理Sindimage
的状态。因此,您还需要将其可见性设置为进入其他块。或者,您可以首先重置视图可见度,然后如下所示。
Because the view holder is being recycled and reused that cause your views to be in the wrong state.
In
SendViewHolder
class you only handle the state ofsentImage
in if block by setting the visibility to visible. Therefore you also need to set its visibility to gone in else block.Or you can reset the view visibility first then show it like below.