From d949cfa7ff195409d05c1c485d884dff0c134d71 Mon Sep 17 00:00:00 2001 From: max Date: Thu, 5 Sep 2024 19:24:44 +0800 Subject: [PATCH] temp save --- .../com/chwl/app/ui/widget/GiftComboLayout.kt | 285 ++++++++++++++++++ app/src/main/res/anim/right_to_left.xml | 7 + .../main/res/layout/fragment_single_room.xml | 2 +- .../main/res/layout/item_gift_combo_view.xml | 104 +++++++ .../java/com/chwl/core/gift/GiftModel.java | 2 +- .../chwl/core/gift/bean/GiftComboInfo.java | 12 + 6 files changed, 410 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/chwl/app/ui/widget/GiftComboLayout.kt create mode 100644 app/src/main/res/anim/right_to_left.xml create mode 100644 app/src/main/res/layout/item_gift_combo_view.xml create mode 100644 core/src/main/java/com/chwl/core/gift/bean/GiftComboInfo.java diff --git a/app/src/main/java/com/chwl/app/ui/widget/GiftComboLayout.kt b/app/src/main/java/com/chwl/app/ui/widget/GiftComboLayout.kt new file mode 100644 index 000000000..238566698 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/GiftComboLayout.kt @@ -0,0 +1,285 @@ +package com.chwl.app.ui.widget + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Handler +import android.os.Looper +import android.os.Message +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.view.animation.Animation +import android.view.animation.AnimationUtils +import android.widget.LinearLayout +import android.widget.TextView +import androidx.core.util.Pools.Pool +import androidx.core.util.Pools.SimplePool +import androidx.core.view.isGone +import androidx.core.view.isVisible +import androidx.cursoradapter.widget.SimpleCursorAdapter.ViewBinder +import androidx.room.util.query +import androidx.viewbinding.ViewBinding +import com.chwl.app.R +import com.chwl.app.databinding.ItemGiftComboViewBinding +import com.chwl.core.gift.bean.GiftComboInfo +import com.opensource.svgaplayer.utils.Pools +import java.util.LinkedList + +class GiftComboLayout @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr, defStyleRes), View.OnClickListener { + + private val showingList = LinkedList() + private val waitingList = LinkedList() + private val comboMap = linkedMapOf() + private val cacheView = SimplePool(2) + private val inflater = LayoutInflater.from(context) + + private val handle = Handler(Looper.getMainLooper()) { + if (it.what == 1) { + viewOut(it.obj as? GiftComboInfo, false) + } + true + } + + init { + + orientation = VERTICAL + + if(isInEditMode){ + inflater.inflate(R.layout.item_gift_combo_view, this, true) + inflater.inflate(R.layout.item_gift_combo_view, this, true) + } + } + + /** + * 创建 + */ + private fun getComboChildView(): ItemGiftComboViewBinding { + val acquire = cacheView.acquire() + if (acquire == null){ + val viewbinding = ItemGiftComboViewBinding.inflate(inflater) + viewbinding.root.apply { + createViewHolder(this) + isVisible = true + } + cacheView.release(viewbinding) + return viewbinding + }else{ + return acquire + } + } + + fun add(giftComboInfo: GiftComboInfo?) { + //没有绑定之前不能添加 + if (!isAttachedToWindow) { + return + } + if (giftComboInfo == null) { + return + } + + var addToWaiting = true + for (comboInfo in showingList) { + if(comboInfo == giftComboInfo){ + comboInfo.giftNumber = giftComboInfo.giftNumber + updateNum(comboInfo) + addToWaiting = false + } + } + + for (comboInfo in waitingList) { + if(comboInfo == giftComboInfo){ + comboInfo.giftNumber = giftComboInfo.giftNumber + addToWaiting = false + } + } + + if(addToWaiting){ + waitingList.add(giftComboInfo) + } + + showNext() + } + + + /** + * 显示下一个 + */ + private fun showNext() { + if(waitingList.isEmpty()){ + return + } + + val comboChildView = getComboChildView() + addView(comboChildView.root,0) + val giftComboInfo = waitingList.remove() + showingList.add(giftComboInfo) + + comboMap[giftComboInfo] = comboChildView + showUi(giftComboInfo) + viewAnimationIn(comboChildView.root) + + handle.sendMessageDelayed(Message.obtain(handle, 1, giftComboInfo), COMBO_STAY_TIME * 1000L) + + if(showingList.size > MAX_SHOWING){ + handle.removeMessages(1, showingList[0]) + viewOut(showingList.remove(), true) + return + } + } + + /** + * 飞入动画 + */ + private fun viewAnimationIn(view: View) { + view.alpha = 1f + view.startAnimation(AnimationUtils.loadAnimation(context, R.anim.right_to_left)) + } + + /** + * 移除动画 + */ + private fun viewOut(giftComboInfo: GiftComboInfo?, isDirectRemove: Boolean) { + giftComboInfo ?: return + val comboView = comboMap.remove(giftComboInfo) ?: return + + val runnable = { + val viewHolder = getViewHolder(comboView) + viewHolder?.clear() + if(!isDirectRemove){ + showingList.remove(giftComboInfo) + } + removeView(comboView) + cacheView.release(comboView) + showNext() + } + + if(isDirectRemove){ + comboView.isGone = true + comboView.post(runnable) + }else{ + val animOut = AnimationUtils.loadAnimation(context, R.anim.alpha_out) + animOut.setAnimationListener(object :SimpleAnimatorListener(){ + override fun onAnimationEnd(animation: Animation) { + comboView.post(runnable) + } + }) + comboView.startAnimation(animOut) + } + } + + /** + * 更新数量 + */ + private fun updateNum(giftComboInfo: GiftComboInfo) { + val view = comboMap[giftComboInfo] ?: return + + val viewHolder = getViewHolder(view) + viewHolder?.refreshNum(giftComboInfo, true) + handle.removeMessages(1, giftComboInfo) + handle.sendMessageDelayed(Message.obtain(handle, 1, giftComboInfo), COMBO_STAY_TIME * 1000L) + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + if(isInEditMode) return + + } + + override fun onRoomCustomMsg(attach: BaseAttach<*>) { + if(attach is NormalGiftAttach){ + val receiveInfo = attach.data ?: return + val comboInfo = GiftComboInfo().apply { + senderUid = receiveInfo.uid + senderName = receiveInfo.nick + senderAvatar = receiveInfo.avatar + receiverName = receiveInfo.targetNicks?.getOrNull(0) + receiverCount = receiveInfo.receiverCount + giftCount = receiveInfo.giftComboCount + giftUrl = receiveInfo.gift?.giftUrl + } + add(comboInfo) + } + } + + @SuppressLint("SetTextI18n") + fun setNextUi(giftComboInfo: GiftComboInfo) { + refreshNum(giftComboInfo) + tvNick.text = giftComboInfo.senderName + tvReceiverNick.text = giftComboInfo.receiverNick + tvNumber.text = "x${giftComboInfo.giftCount}" + ivGift.load(giftComboInfo.giftUrl) + ivAvatar.load(giftComboInfo.senderAvatar) + ivAvatar.tag = giftComboInfo + } + + /** + * 用于刷新数量 + */ + @SuppressLint("SetTextI18n") + fun reSetNum(giftComboInfo: GiftComboInfo, isAnim: Boolean = false) { + val num = giftComboInfo.giftCount + if(num == 0){ + tvNumber.isVisible = false + return + } + val old = tvNumber.tag as? Int + //兼容上一个比下一个数还要大 + if (old != null && old > num) { + return + } + tvNumber.isVisible = true + tvNumber.tag = num + tvNumber.text = "x$num" + if (isAnim) { + tvNumber.animate().cancel() + tvNumber.scaleX = 1.3f + tvNumber.scaleY = 1.3f + tvNumber.animate() + .scaleX(1f) + .scaleY(1f) + .start() + } + } + + + + fun reSetUi() { + tvNumber.animate().cancel() + tvNumber.tag = 0 + ivAvatar.tag = null + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + handle.removeCallbacksAndMessages(null) + } + + + + companion object { + /** + * 最大显示个数 + */ + const val MAX_SHOWING = 2 + + /** + * 连击停留时间 + */ + const val COMBO_STAY_TIME = 5 + } + +// override fun onClick(v: View) { +// val giftComboInfo = v.tag as? GiftComboInfo ?: return +// val sendUid = giftComboInfo.sentUserid +// if (sendUid == 0L) { +// return +// } +//// RoomUserInfoDialog.show(sendUid) +// } + +} \ No newline at end of file diff --git a/app/src/main/res/anim/right_to_left.xml b/app/src/main/res/anim/right_to_left.xml new file mode 100644 index 000000000..8d8d9e2b6 --- /dev/null +++ b/app/src/main/res/anim/right_to_left.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_single_room.xml b/app/src/main/res/layout/fragment_single_room.xml index 3aad11131..ec9c1782d 100644 --- a/app/src/main/res/layout/fragment_single_room.xml +++ b/app/src/main/res/layout/fragment_single_room.xml @@ -257,7 +257,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.0" - tools:visibility="visible"> + tools:visibility="gone"> + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/src/main/java/com/chwl/core/gift/GiftModel.java b/core/src/main/java/com/chwl/core/gift/GiftModel.java index 62a0a6abd..f47586fbe 100644 --- a/core/src/main/java/com/chwl/core/gift/GiftModel.java +++ b/core/src/main/java/com/chwl/core/gift/GiftModel.java @@ -124,7 +124,7 @@ public class GiftModel extends BaseModel implements IGiftModel { private void addGiftMessage(CustomAttachment attachment) { giftQueue.add(attachment); if (giftQueue.size() == 1) { - handler.sendEmptyMessageDelayed(0, 150); + handler.sendEmptyMessageDelayed(0, 200); } } diff --git a/core/src/main/java/com/chwl/core/gift/bean/GiftComboInfo.java b/core/src/main/java/com/chwl/core/gift/bean/GiftComboInfo.java new file mode 100644 index 000000000..51fdfb89f --- /dev/null +++ b/core/src/main/java/com/chwl/core/gift/bean/GiftComboInfo.java @@ -0,0 +1,12 @@ +package com.chwl.core.gift.bean; + +public class GiftComboInfo { + public long sentUserid; + public String sentUserName; + public String sentAvatar; + public String giftImgUrl; + public int giftNumber; + public int receiverNumber; + public String receiverUserName; + +}