首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >添加新消息时,RecyclerView滚动到向下。

添加新消息时,RecyclerView滚动到向下。
EN

Stack Overflow用户
提问于 2022-09-01 11:33:37
回答 3查看 59关注 0票数 0

我有个聊天应用。我使用RecyclerView,并将stackFromEnd设置为true,将reverseLayout false设置为LinearlayoutManager。当在底部添加新消息时,我的意思是在列表的末尾,recyclerView开始自动向下滚动,而不是向上滚动。适配器由notifyItemInserted()通知。

预期行为:当新消息被添加到列表中时,它应该滚动到底部或向上。任何帮助都是非常感谢的。谢谢,

下面是适配器:

代码语言:javascript
运行
复制
class ChatMessagesListAdapter(
    var chatMessages: ChatMessagesDataModel
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    companion object {
        // we set the header as 0 so we can add more types to the ConversationItem enum
        private const val ITEM_TYPE_HEADER = 0
    }


    override fun getItemViewType(position: Int): Int {
        return when {
            chatMessages.hasMoreItems -> chatMessages.messages[position].getItemType()
            position == 0 -> ITEM_TYPE_HEADER
            else -> chatMessages.messages[position - 1].getItemType()
        }
    }

    // return +1 to draw the header if there are no items to load
    override fun getItemCount() = chatMessages.messages.size + getContentIndex()

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val inflater = LayoutInflater.from(parent.context)

        return when (viewType) {
            ITEM_TYPE_HEADER -> {
                MessagesHeaderViewHolder(inflater.inflate(R.layout.item_chat_messages_header,
                    parent, false))
            }

            ChatItemDataModel.TYPE_ADDED_USER,
            ChatItemDataModel.TYPE_VIDEO_NOTIFICATION -> {
                MessagesInfoViewHolder(inflater.inflate(R.layout.item_chat_messages_info,
                    parent, false))
            }
            else -> {
                MessagesMessageViewHolder(inflater.inflate(R.layout.item_chat_messages_message,
                    parent, false))
            }
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        (holder as? MessagesHeaderViewHolder)?.bind()
        (holder as? MessagesMessageViewHolder)?.bind(position, chatMessages.messages[getRealPosition(position)])
        (holder as? MessagesInfoViewHolder)?.bind(chatMessages.messages[getRealPosition(position)])
    }

    private fun getContentIndex() = if (chatMessages.hasMoreItems) {
        0
    } else {
        1
    }

    private fun getRealPosition(position: Int) = if (chatMessages.hasMoreItems) {
        position
    } else {
        position - 1
    }

    private fun notifyChanges() {
        if (chatMessages.numberOfItemsInserted == chatMessages.messages.size || isPreview ||
            chatMessages.hadPendingMessages) {
            notifyDataSetChanged()
        } else {
            // +1 because of the header
            notifyItemRangeInserted(chatMessages.insertionIndex + getContentIndex(),
                chatMessages.numberOfItemsInserted)
        }
    }

    fun updateConversation(newChatMessages: ChatMessagesDataModel) {
        chatMessages = newChatMessages
        notifyChanges()
    }

    fun updateMessage(newMessage: ChatItemDataModel, isRemote: Boolean) {
        if (newMessage.message.hashIdentifier.isNullOrBlank()) {
            addNewMessage(newMessage)
            return
        }
        val messageIndex = chatMessages.messages.indexOfFirst { it.message.hashIdentifier == newMessage.message.hashIdentifier }

        if (messageIndex != -1) {
            val localMessage =  chatMessages.messages[messageIndex]
            chatMessages.messages[messageIndex] = newMessage

            if (failedMessages.contains(localMessage.message.sid)) {
                if (isRemote) {
                    failedMessages.remove(localMessage.message.sid)
                }
                notifyItemChanged(messageIndex + getContentIndex())
            }
        }
        else {
            addNewMessage(newMessage)
        }
    }

    private fun addNewMessage(newMessage: ChatItemDataModel) {
        val oldCount = chatMessages.messages.size
        chatMessages.messages.add(newMessage)
        notifyItemInserted(oldCount + getContentIndex())
    }

    fun addLocalMessage(
        sharedPrefsStorage: SharedPrefsStorage,
        message: String, imageUri: Uri?, hashIdentifier: String
    ) {
        val userMessage = UserMessage(messageBody = message, firstName = sharedPrefsStorage.firstName,
            lastName = sharedPrefsStorage.lastName, isFromLoggedUser = true, imageUri = imageUri,
            hashIdentifier = hashIdentifier, files = null, reactions = null)

        val newMessage = ChatItemDataModel(userMessage, sharedPrefsStorage.profileImageUrl, sharedPrefsStorage.userId.toString())
        val oldCount = chatMessages.messages.size
        chatMessages.messages.add(newMessage)
        notifyItemRangeInserted(oldCount + getContentIndex(), 1)
    }
           ....
}

以下是片段:

代码语言:javascript
运行
复制
class ChatRoomMessagesFragment : Fragment() {

    @Inject
    lateinit var sharedPrefsStorage: SharedPrefsStorage

    private var adapter: ChatMessagesListAdapter? = null

           ......
override fun onMessagesReceived(chatMessages: ChatMessagesDataModel) {
        if (adapter == null) {
            adapter = ChatMessagesListAdapter(chatMessages)

            adapter?.setHasStableIds(true)
            binding.recyclerview.adapter = adapter
        } else {
            adapter?.updateConversation(chatMessages)
        }
    }

override fun onUserMessageRetrieved(newMessage: ChatItemDataModel, isRemote: Boolean) {
        adapter?.updateMessage(newMessage, isRemote)
    }

    private fun setupUI() {

        binding.apply {

            recyclerview.apply {
                layoutManager = LinearLayoutManager(requireContext()).apply {
                    reverseLayout = false
                    stackFromEnd = true
                    addOnScrollListener(object : RecyclerView.OnScrollListener() {
                        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                            super.onScrolled(recyclerView, dx, dy)
                            showScrollToBottomButtonIfNeeded(findFirstCompletelyVisibleItemPosition())
                        }
                    })
                }

                addOnScrollListener(object : PaginationScrollListener(
                    layoutManager as LinearLayoutManager,
                    ScrollDirection.BOTTOM
                ) {

                    override fun loadMoreItems() {
                        presenter.loadMoreMessages()
                    }

                    override fun isLastPage() = !presenter.hasMoreItems()

                    override fun isLoading() = presenter.isLoadingInProgress()
                })

                // prevent the list from scrolling when the keyboard opens
                addOnLayoutChangeListener { _, _, _, _, bottom, _, _, _, oldBottom ->
                    if (bottom < oldBottom) {
                        scrollChatToBottom()
                    }
                }
            }
       ....
                adapter?.addLocalMessage(sharedPrefsStorage, message, imageUri, hashIdentifier)
                presenter.sendMessage("", message, imageUri, hashIdentifier)
}

 private fun scrollChatToBottom() {
        binding.apply {
            recyclerview.post {
                recyclerview.smoothScrollToPosition(recyclerview.adapter?.itemCount ?: 0)
            }
        }
    }



}
EN

Stack Overflow用户

发布于 2022-09-01 13:59:35

代码语言:javascript
运行
复制
 yourAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
            override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
                super.onItemRangeInserted(positionStart, itemCount)
                this@EventDetails.binding.rvData.scrollToPosition(positionStart)
            }

            override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
                super.onItemRangeChanged(positionStart, itemCount)
                this@EventDetails.binding.rvData.scrollToPosition(positionStart)
            }
        })

这些方法中的一种会奏效--我认为第一种方法,尝试避免使用notifyDataSetChange()或intemChange()调用您自己使用的DiffUtils或ListAdapter(扩展回收器视图)。

票数 0
EN
查看全部 3 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73568673

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档