【问题标题】:Swipe to reply in chat message like whats app programmatically in android滑动以在 android 中以编程方式在聊天消息中回复,例如 whats 应用程序
【发布时间】:2021-09-01 01:07:06
【问题描述】:

我目前正在开发聊天应用程序。我需要滑动才能以编程方式回复特定消息,例如 android 中的 WhatsApp。请帮助我实现这一目标。提前致谢。

链接我指的是 https://github.com/shainsingh89/SwipeToReply.

【问题讨论】:

    标签: android kotlin android-recyclerview chat swipe-gesture


    【解决方案1】:

    好吧,在这里我将列出所提出的解决方案的主要挑战,您可以在github over here找到整个项目:

    挑战 1:带有引用文本的新布局

    1. 为发送者和接收者添加两个新的聊天消息布局 send_message_quoted_rowreceived_message_quoted_row ->> 布局可以比这更好,但现在没什么大不了的。

    2. 修改MessageAdapter以接受它们为新类型,并更新onBindViewHolder中的引用文本:

        private fun getItemViewType(message: Message): Int {
            return if (message.type == MessageType.SEND)
                if (message.quotePos == -1) R.layout.send_message_row
                else R.layout.send_message_quoted_row
            else
                if (message.quotePos == -1) R.layout.received_message_row
                else R.layout.received_message_quoted_row
        }
    
        override fun onBindViewHolder(holder: MessageViewHolder, position: Int) {
            val message = messageList[position]
            holder.txtSendMsg.text = message.body
            holder.txtQuotedMsg?.text = message.quote
        }
    
        class MessageViewHolder(view: View) : RecyclerView.ViewHolder(view) {
            var txtSendMsg = view.txtBody!!
            var txtQuotedMsg: TextView? = view.textQuote
        }
    
    1. Message数据类添加新的构造函数以接受原始消息的引用和位置(在当前消息中被引用
    data class Message(var body: String, var time: Long, var type: Int) {
    
        var quote: String = ""
        var quotePos: Int = -1
    
        constructor(
            body: String,
            time: Long,
            type: Int,
            quote: String,
            quotePos: Int
        ) : this(body, time, type) {
            this.quote = quote
            this.quotePos = quotePos
        }
    
    }
    
    object MessageType {
        const val SEND = 1
        const val RECEIVED = 2
    }
    
    1. SampleMessages 中添加用于测试的示例引用消息

    挑战 2:将引用布局嵌入到回复布局中,例如 WhatsApp 动画

    在 WhatsApp 中:引用布局作为回复布局的一部分出现,并逐渐从原始布局的底部到顶部。此外,当按下取消按钮时,它会将动画反转到底部。

    • 通过更改引用的TextView 的高度,然后使用 View.Gone/Visible 显示布局,使用自定义动画类解决。
    class ResizeAnim(var view: View, private val startHeight: Int, private val targetHeight: Int) :
        Animation() {
    
        override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
            if (startHeight == 0 || targetHeight == 0) {
                view.layoutParams.height =
                    (startHeight + (targetHeight - startHeight) * interpolatedTime).toInt()
            } else {
                view.layoutParams.height = (startHeight + targetHeight * interpolatedTime).toInt()
            }
            view.requestLayout()
        }
    
        override fun willChangeBounds(): Boolean {
            return true
        }
    }
    

    并在活动showQuotedMessage()hideReplyLayout()中处理这个动画

    private fun hideReplyLayout() {
    
        val resizeAnim = ResizeAnim(reply_layout, mainActivityViewModel.currentMessageHeight, 0)
        resizeAnim.duration = ANIMATION_DURATION
    
        Handler().postDelayed({
            reply_layout.layout(0, -reply_layout.height, reply_layout.width, 0)
            reply_layout.requestLayout()
            reply_layout.forceLayout()
            reply_layout.visibility = View.GONE
    
        }, ANIMATION_DURATION - 50)
    
        reply_layout.startAnimation(resizeAnim)
        mainActivityViewModel.currentMessageHeight = 0
    
        resizeAnim.setAnimationListener(object : Animation.AnimationListener {
            override fun onAnimationStart(animation: Animation?) {
            }
    
            override fun onAnimationEnd(animation: Animation?) {
                val params = reply_layout.layoutParams
                params.height = 0
                reply_layout.layoutParams = params
            }
    
            override fun onAnimationRepeat(animation: Animation?) {
            }
        })
    
    }
    
    private fun showQuotedMessage(message: Message) {
        edit_message.requestFocus()
        val inputMethodManager =
            getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        inputMethodManager.showSoftInput(edit_message, InputMethodManager.SHOW_IMPLICIT)
    
        textQuotedMessage.text = message.body
        val height = textQuotedMessage.getActualHeight()
        val startHeight = mainActivityViewModel.currentMessageHeight
    
        if (height != startHeight) {
    
            if (reply_layout.visibility == View.GONE)
                Handler().postDelayed({
                    reply_layout.visibility = View.VISIBLE
                }, 50)
    
            val targetHeight = height - startHeight
    
            val resizeAnim =
                ResizeAnim(
                    reply_layout,
                    startHeight,
                    targetHeight
                )
    
            resizeAnim.duration = ANIMATION_DURATION
            reply_layout.startAnimation(resizeAnim)
    
            mainActivityViewModel.currentMessageHeight = height
    
        }
    
    }
    
    private fun TextView.getActualHeight(): Int {
        textQuotedMessage.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
        return this.measuredHeight
    }
    

    挑战3:计算新引用文字高度的真实值

    特别是当用户在当前有引用的消息时滑动不同高度的另一条消息时需要扩展/缩小引用的文本高度。

    • 使用getHeight() 函数以编程方式对引用的TextView 进行处理,并将其文本设置为新文本,将其高度与旧文本的高度进行比较,并相应地操作动画。

    • 这已经在顶级方法中介绍过,我使用 currentMessageHeight 整数跟踪 ViewModel 中的旧高度。

    挑战 4:将OnClickListener 添加到引用的消息中

    • 所以要回到引用消息的原始位置,我们在Message类中注册这个作为一个字段,当它是-1时,那么它不是引用消息;否则为引用消息。
    • 点击监听器使用MessageAdapter 中的自定义QuoteClickListener 接口进行处理

    预览:

    添加新消息:

    【讨论】:

    • 我正在准备项目在github上,很快会添加repo
    • @Zain-让我试试这个样本。非常感谢
    • @Kumar HYG this is the forked github 克隆并享受.. 相信我这花了我一整天的时间才能让它工作
    【解决方案2】:

    您应该阅读本文以滑动以回复聊天消息,希望对您有所帮助 https://medium.com/mindorks/swipe-to-reply-android-recycler-view-ui-c11365f8999f

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多