在 android 中以编程方式滑动以回复聊天消息,例如 whats app
Swipe to reply in chat message like whats app programmatically in android
我目前正在开发聊天应用程序。我需要滑动才能以编程方式回复 android 中的 WhatsApp 等特定消息。请帮助我实现这一目标。提前致谢。
link我指的是
https://github.com/shainsingh89/SwipeToReply.
你应该阅读这篇滑动回复聊天消息希望它能帮助你
https://medium.com/mindorks/swipe-to-reply-android-recycler-view-ui-c11365f8999f
好吧,在这里我将列出主要挑战和建议的解决方案,您可以在 github over here:
上找到整个项目
挑战 1:带有引用文本的新布局
为发送者和接收者添加两个新的聊天消息布局 send_message_quoted_row
& received_message_quoted_row
->> 布局可能比这更好,但对现在。
修改 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
}
- 向
Message
数据添加新构造函数 class 以接受引用和原始消息的位置(在当前消息中被引用
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
}
- 在
SampleMessages
中添加用于测试的示例引用消息
挑战 2:将引用布局嵌入到像 WhatsApp 一样动画的回复布局中
在WhatsApp中:引用版面作为回复版面的一部分出现,在原版面之后从下往上逐渐出现。此外,当按下取消按钮时,它会将动画反转到底部。
- 通过使用自定义动画解决 class 通过更改引用
TextView
的高度,然后使用视图。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
}
}
并在 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
}
挑战三:计算新引用文字高度的真实值
特别是当用户在当前有引用消息的情况下滑动另一条不同高度的消息时需要引用文本高度需要expanded/shrink。
通过使用 getHeight()
函数以编程方式膨胀引用的 TextView
并将其文本设置为新文本,将其高度与旧文本的高度进行比较,以及相应地操纵动画。
这已经包含在顶级方法中,我使用 currentMessageHeight
整数跟踪 ViewModel 中的旧高度。
挑战 4:将 OnClickListener
添加到引用的消息中
- 所以要转到引用消息的原始位置,我们在
Message
class中将其注册为一个字段,当它是-1时,则不是引用消息;否则它是引用消息。
- 点击侦听器由
MessageAdapter
中的自定义 QuoteClickListener
界面处理
预览:
添加新消息:
我目前正在开发聊天应用程序。我需要滑动才能以编程方式回复 android 中的 WhatsApp 等特定消息。请帮助我实现这一目标。提前致谢。
link我指的是 https://github.com/shainsingh89/SwipeToReply.
你应该阅读这篇滑动回复聊天消息希望它能帮助你 https://medium.com/mindorks/swipe-to-reply-android-recycler-view-ui-c11365f8999f
好吧,在这里我将列出主要挑战和建议的解决方案,您可以在 github over here:
上找到整个项目挑战 1:带有引用文本的新布局
为发送者和接收者添加两个新的聊天消息布局
send_message_quoted_row
&received_message_quoted_row
->> 布局可能比这更好,但对现在。修改
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
}
- 向
Message
数据添加新构造函数 class 以接受引用和原始消息的位置(在当前消息中被引用
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
}
- 在
SampleMessages
中添加用于测试的示例引用消息
挑战 2:将引用布局嵌入到像 WhatsApp 一样动画的回复布局中
在WhatsApp中:引用版面作为回复版面的一部分出现,在原版面之后从下往上逐渐出现。此外,当按下取消按钮时,它会将动画反转到底部。
- 通过使用自定义动画解决 class 通过更改引用
TextView
的高度,然后使用视图。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
}
}
并在 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
}
挑战三:计算新引用文字高度的真实值
特别是当用户在当前有引用消息的情况下滑动另一条不同高度的消息时需要引用文本高度需要expanded/shrink。
通过使用
getHeight()
函数以编程方式膨胀引用的TextView
并将其文本设置为新文本,将其高度与旧文本的高度进行比较,以及相应地操纵动画。这已经包含在顶级方法中,我使用
currentMessageHeight
整数跟踪 ViewModel 中的旧高度。
挑战 4:将 OnClickListener
添加到引用的消息中
- 所以要转到引用消息的原始位置,我们在
Message
class中将其注册为一个字段,当它是-1时,则不是引用消息;否则它是引用消息。 - 点击侦听器由
MessageAdapter
中的自定义
QuoteClickListener
界面处理
预览:
添加新消息: