androidkotlinandroid-recyclerviewchatswipe-gesture

Swipe to reply in chat message like whats app programmatically in android


I am currently working on chat application. I need swipe to reply a particular message like WhatsApp in android programmatically. kindly help me to achieve this. thanks in advance.

link I am referring https://github.com/shainsingh89/SwipeToReply.

swipe to reply


Solution

  • Well, here I will list the main challenges with the proposed solutions, you can find the entire project on the github over here:

    Challenge 1: New layouts with the quoted text

    1. Adding two new chat message layouts for the sender & receiver send_message_quoted_row & received_message_quoted_row ->> The layout can just be better than that but it's not a big deal for now.

    2. Modifying MessageAdapter to accept them as a new type, and update the quote text in 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. Adding new constructor to the Message data class to accept the quote and the position of the original message (which is quoted in the current 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. Adding sample quoted messages for testing in SampleMessages

    Challenge 2: Embed the quote layout into the reply layout animated like WhatsApp

    In WhatsApp: the quote layout appears as a part of the reply layout, and it gradually comes from bottom to top behind the original layout. Also when the cancel button is pressed, it reverses the animation to the bottom.

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

    And handle this animation within the activity 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
    }
    

    Challenge 3: Calculating the real value of the new quoted text height

    Especially when the quoted text height need to be expanded/shrink when the user swipes another message of a different height while there is currently a quoted message.

    Challenge 4: Adding OnClickListener to the quoted message

    Preview:

    Adding a new Message: