当前位置: 首页 > 知识库问答 >
问题:

当滚动图片时,视图混乱

呼延珂
2023-03-14

我正在开发一个聊天应用程序。我有一个聊天活动,两个用户可以发送WhatsApp之类的消息,但我有个问题。

就像你在图中看到的(https://ibb.co/3cyYX01),滚动时视图乱糟糟的,我想我知道为什么了。

在查看了这些帖子后:RecyclerView在滚动时出错,Android:RecyclerView在滚动后内容出错

我假设问题可能出在函数onBindViewHolder中的回收器视图适配器中,因为我在某些视图(VIEW.GONE和VIEW.VISIBLE)上使用了可见性选项,并且我认为这些视图正在以错误的可见性重新绘制。

此外,我在< code>onBindViewHolder中使用了< code > holder . setisrecyclable(false),以便检查是否是回收部分导致了问题,并且当我使用它时,它工作得很好。

这是RecyclerView适配器:

    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()
}


}

粘贴链接: https://pastebin.com/Ri5pUAdk

非常感谢。

共有2个答案

姜锋
2023-03-14
匿名用户

因为视图持有者正在被回收和重用,导致您的视图处于错误状态。

在< code>SendViewHolder类中,您只需通过将visibility设置为visible来处理if块中的< code > senimage 的状态。因此,您还需要在else块中将它的可见性设置为gone。

或者您可以先重置视图可见性,然后像下面这样显示它。

fun bindSendRow(message: Message) {
    sentMessageTextView.visibility = View.GONE
    sentImage.visibilty = View.GONE
    if(shouldShowImage){
        sentImage.visibility = View.VISIBLE
    } else if(shouldShowText){
        sentMessageTextView.visibility = View.VISIBLE
    }
}

亢仰岳
2023-03-14

< code > recycle view 的工作就是基于此,它回收视图来显示列表。当您滚动时,屏幕外的< code >视图不会被销毁,而是再次被重新使用以显示新的列表项目。因此,如果您更改视图的< code>visibility或任何其他属性,并且不在< code>onBindViewHolder中再次重置它,那么它将显示在回收之前设置的所有属性。

fun bind(data: Data) {
    val textView = itemView.findViewById<TextView>(R.id.tvText)
    if(data.text.isEmpty()) {
        textView.visibility = View.GONE
    }
}

在上述方法中,当文本为时,我们隐藏文本视图,但我们没有在条件中设置任何内容。因此,当视图(我们已将可见性设置为消失了)将被回收时,它们将永远不会显示文本视图 ,因为它正在重用查看 。为了解决这个问题,我们必须分别为<code>true</code>和<code>false</code>条件设置视图的属性。

fun bind(data: Data) {
    val textView = itemView.findViewById<TextView>(R.id.tvText)
    if(data.text.isEmpty()) {
        textView.visibility = View.GONE
    } else {
        textView.visibility = View.VISIBLE
    }
}

SentViewHolderReceivedViewHolder 中,您将 ImageView 的可见性设置为可见

sentImage.visibility = View.VISIBLE

receiveImage.visibility = View.VISIBLE

但您从未将其设置为<code>消失</code>。

在< code >(message . message . equals(" Sent you a image ")的else条件中

 类似资料:
  • 利用UIScrollView实现视差滚动效果。在demo中,滑动ScrollView,背景图和文字的滚动速度不一样。直接用ScrollView 的协议,对其子视图的坐标进行随机系数比例的位置移动修正,从而实现视差滚动效果。没有用其他的框架,代码简单。 作者说:原创Demo 转载请注明出处。 [Code4App.com]

  • 问题内容: 我有一个用CSS3进行动画处理的条形图,当前该动画在页面加载时激活。 我的问题是,由于之前有很多内容,因此给定的条形图不在屏幕上,因此当用户向下滚动到该条形图时,动画已经结束。 我正在寻找通过CSS3或jQuery仅在查看者看到图表时激活条形图上的CSS3动画的方法。 如果在页面加载后立即快速向下滚动,则可以看到该动画。 另外,我不知道这是否重要,但是我在页面上有此条形图的多个实例。

  • 我试图实现某种排序工具栏-但没有工具栏(而不是工具栏,它将是一个下拉元素,它本质上是一个RelativeLayout,其正下方有LinearLayout(下拉列表中的扩展项目),一旦按下下拉菜单,它就会在整个布局上悬停。 我考虑过实现折叠工具栏并将下拉列表放入工具栏中,但这可能不是一个好主意,因为下拉列表不是像图像视图这样的静态组件。我还在我的应用程序中使用了ActionBar,因此迁移到工具栏很

  • 我有一个水平ScrollView,它有两个元素:CardView和水平RecycerView。所以,当用户水平滚动时,我希望这两个元素滚动。 我想有这样的东西:Goal,橙色的线是CardView,黄色的线是RecycerView。当用户滚动时,两个元素滚动,如下所示:Scrolled Goal。 现在在我的应用程序中,当用户滚动时,只有RecycerView滚动。CardView保持在他的位置。

  • 实现循环ScrollView。有以下特色: 1、循环的scrollview 2、类似于tableview的编程方式 3、可定制化的内容 4、灵活运用可用于移步加载图片 5、结构化,可扩展性高 [Code4App.com]

  • 我有一个当用户滚动时显示隐藏单元格的tableView。不确定为什么会出现这种情况。 在视图中DidLoad() 用户点击按钮后,表格将以可设置动画的方式展开。 在 func tableView(_ tableView: UITableView, cellForRowAt 索引路径: 索引路径) - 当我滚动时,所有单元格都被隐藏。我看到它们是在单元格中创建的,但是,它们不会出现在我的屏幕上。为什