feat:完成特权卡动画修改,支持mp4播放

This commit is contained in:
Max
2023-11-03 16:47:59 +08:00
parent 529d1500ba
commit 15cf083657
11 changed files with 332 additions and 61 deletions

View File

@@ -205,8 +205,9 @@ class CreatePrivilegeCardDialog : BaseDialog<DialogCreatePrivilegeCardBinding>()
this,
canChooseGif = true,
resultCode = REQUEST_CODE_OPEN_PHOTO_PROVIDER,
maxFileSize = 1024 * 1024 * 100,
maxFileSize = 1024 * 1024 * 20,
videoMaxSecond = 15,
showVideoType = "mp4"
)
}
binding.tvCancel.setOnClickListener {
@@ -440,7 +441,7 @@ class CreatePrivilegeCardDialog : BaseDialog<DialogCreatePrivilegeCardBinding>()
val saveResult = com.chuhai.utils.ImageUtils.save(
resource,
outPath,
Bitmap.CompressFormat.JPEG, true
Bitmap.CompressFormat.JPEG, false
)
if (saveResult) {
Log.d(TAG, "uploadVideo 封面保存成功")

View File

@@ -24,7 +24,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.netease.nim.uikit.common.util.log.LogUtil;
import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage;
import com.nnbc123.app.R;
@@ -99,8 +98,11 @@ public class GiftV2View extends FrameLayout implements GiftEffectView.GiftEffect
private int mScreenWidth;
private int mScreenHeight;
private Keyframe[] keyScale;
private Keyframe[] privilegeCardKeyScale;
private Keyframe[] privilegeCardKeyTransY;
private Keyframe[] keyTrans;
private SvgaObjectPool mMagicViewPool;
private PrivilegeCardEngine privilegeCardEngine;
private volatile Hashtable<Integer, MonsterAttackInfo> currentAnimationMap = new Hashtable<>();
@@ -126,8 +128,8 @@ public class GiftV2View extends FrameLayout implements GiftEffectView.GiftEffect
mScreenHeight = ResolutionUtils.getScreenHeight(getContext());
giftWidth = UIUtil.dip2px(context, 80);
giftHeight = UIUtil.dip2px(context, 80);
privilegeWidth = UIUtil.dip2px(context, 120);
privilegeHeight = UIUtil.dip2px(context, 68);
privilegeWidth = UIUtil.dip2px(context, 240);
privilegeHeight = UIUtil.dip2px(context, 136);
keyScale = new Keyframe[7];
keyScale[0] = (Keyframe.ofFloat(0f, 1f));
@@ -142,6 +144,18 @@ public class GiftV2View extends FrameLayout implements GiftEffectView.GiftEffect
keyTrans[1] = (Keyframe.ofFloat(0.2f, 0));
keyTrans[2] = (Keyframe.ofFloat(0.3f, 0));
privilegeCardKeyScale = new Keyframe[4];
privilegeCardKeyScale[0] = (Keyframe.ofFloat(0f, 0f));
privilegeCardKeyScale[1] = (Keyframe.ofFloat(0.08f, 1f));
privilegeCardKeyScale[2] = (Keyframe.ofFloat(0.92f, 1f));
privilegeCardKeyScale[3] = (Keyframe.ofFloat(1f, 0f));
privilegeCardKeyTransY = new Keyframe[4];
int showY = mScreenHeight / 2 - mScreenHeight - privilegeHeight / 2;
privilegeCardKeyTransY[0] = (Keyframe.ofFloat(0f, 0));
privilegeCardKeyTransY[1] = (Keyframe.ofFloat(0.08f, showY));
privilegeCardKeyTransY[2] = (Keyframe.ofFloat(0.92f, showY));
privilegeCardKeyTransY[3] = (Keyframe.ofFloat(1f, 0));
giftEffectInfoList = new ArrayList<>();
mMagicReceivedInfos = new ArrayList<>();
giftEffectView = findViewById(R.id.gift_effect_view);
@@ -149,6 +163,7 @@ public class GiftV2View extends FrameLayout implements GiftEffectView.GiftEffect
giftEffectView.setGiftEffectListener(this);
handler = new UiHandler(this);
mMagicViewPool = new SvgaObjectPool(this);
privilegeCardEngine = new PrivilegeCardEngine(this, privilegeWidth, privilegeHeight);
}
public void onReceiveMultiGiftMsg(MultiGiftReceiveInfo multiGiftReceiveInfo) {
@@ -576,22 +591,18 @@ public class GiftV2View extends FrameLayout implements GiftEffectView.GiftEffect
RoomPrivilegeAttachment msgInfo = ((RoomPrivilegeAttachment) message.getAttachment());
if (msgInfo == null) return;
SparseArray<Point> micViewPoint = AvRoomDataManager.get().mMicPointMap;
if (micViewPoint == null) {
//产生空的原因是麦位坐标初始化有500ms延迟
LogUtil.print("gift micViewPoint is null");
if (!AvRoomDataManager.get().mIsNeedGiftEffect ||
AvRoomDataManager.get().isSelfGamePlaying()) {
return;
}
Point senderPoint = new Point(UIUtil.getScreenWidth(context) / 2 - privilegeWidth / 2,
UIUtil.getScreenHeight(context) / 2);
//礼物送到上面中间的位置
Point receivePoint = new Point(UIUtil.getScreenWidth(context) / 2 - privilegeWidth / 2,
UIUtil.getScreenHeight(context));
drawPrivilegeGiftView(senderPoint, receivePoint, msgInfo.getCardUrl());
if (msgInfo.getCardType() == 2) {
// 视频类型
privilegeCardEngine.onPrivilegeSignaling(msgInfo);
} else {
// 其他类型继续走之前的老逻辑PS后续熟悉房间代码后再把这部分老代码迁移到privilegeCardEngine中吧
drawPrivilegeGiftView(msgInfo.getCardUrl());
}
}
}
private void drawGiftEffect(GiftEffectInfo giftEffectInfo) {
@@ -790,7 +801,7 @@ public class GiftV2View extends FrameLayout implements GiftEffectView.GiftEffect
});
}
private void drawPrivilegeGiftView(Point senderPoint, Point receivePoint, String giftUrl) {
private void drawPrivilegeGiftView(String giftUrl) {
if (!AvRoomDataManager.get().mIsNeedGiftEffect ||
AvRoomDataManager.get().isSelfGamePlaying()) {
return;
@@ -798,30 +809,16 @@ public class GiftV2View extends FrameLayout implements GiftEffectView.GiftEffect
if (giftUrl == null) {
return;
}
final Point center = new Point();
center.x = context.getResources().getDisplayMetrics().widthPixels / 2;
center.y = context.getResources().getDisplayMetrics().heightPixels / 2;
if (senderPoint == null || isGameRoomMoreThan6People()) {
senderPoint = new Point(mScreenWidth / 2 - privilegeWidth / 2, UIUtil.dip2px(context, 25));
}
SVGAImageView imageView = mMagicViewPool.borrowPrivilegeObject(senderPoint);
Point firstPoint = new Point(mScreenWidth / 2 - privilegeWidth / 2,
mScreenHeight);
SVGAImageView imageView = mMagicViewPool.borrowPrivilegeObject(firstPoint);
GlideUtils.instance().loadGiftAndCrossFadeRound(
giftUrl, imageView, 8f);
Keyframe keyTransX3 = (Keyframe.ofFloat(0.5f, center.x - senderPoint.x - privilegeWidth / 2));
Keyframe keyTransX4 = (Keyframe.ofFloat(0.8f, center.x - senderPoint.x - privilegeWidth / 2));
Keyframe keyTransX5 = (Keyframe.ofFloat(1f, receivePoint.x - senderPoint.x));
Keyframe keyTransY3 = (Keyframe.ofFloat(0.5f, center.y - senderPoint.y - privilegeHeight / 2));
Keyframe keyTransY4 = (Keyframe.ofFloat(0.8f, center.y - senderPoint.y - privilegeHeight / 2));
Keyframe keyTransY5 = (Keyframe.ofFloat(1f, receivePoint.y - senderPoint.y));
PropertyValuesHolder p0 = PropertyValuesHolder.ofKeyframe("translationX", keyTrans[0], keyTrans[1], keyTrans[2], keyTransX3, keyTransX4, keyTransX5);
PropertyValuesHolder p1 = PropertyValuesHolder.ofKeyframe("translationY", keyTrans[0], keyTrans[1], keyTrans[2], keyTransY3, keyTransY4, keyTransY5);
PropertyValuesHolder p2 = PropertyValuesHolder.ofKeyframe("scaleX", keyScale);
PropertyValuesHolder p3 = PropertyValuesHolder.ofKeyframe("scaleY", keyScale);
ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(imageView, p2, p3, p1, p0);
objectAnimator.setDuration(3200);
PropertyValuesHolder p1 = PropertyValuesHolder.ofKeyframe("translationY", privilegeCardKeyTransY);
PropertyValuesHolder p2 = PropertyValuesHolder.ofKeyframe("scaleX", privilegeCardKeyScale);
PropertyValuesHolder p3 = PropertyValuesHolder.ofKeyframe("scaleY", privilegeCardKeyScale);
ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(imageView, p2, p3, p1);
objectAnimator.setDuration(6000);
objectAnimator.start();
objectAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -831,6 +828,7 @@ public class GiftV2View extends FrameLayout implements GiftEffectView.GiftEffect
});
}
private boolean isGameRoomMoreThan6People() {
RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo;
return AvRoomDataManager.get().isOpenGame() && roomInfo != null && roomInfo.getMgMicNum() > 6;
@@ -858,6 +856,7 @@ public class GiftV2View extends FrameLayout implements GiftEffectView.GiftEffect
mMagicExplodeView.stopAnimation();
mMagicExplodeView.clearAnimation();
mMagicViewPool.shutdown();
privilegeCardEngine.onCleared();
}
@Override
@@ -883,7 +882,6 @@ public class GiftV2View extends FrameLayout implements GiftEffectView.GiftEffect
mSVGAVideoEntityMap.put(url, videoEntity);
}
private static class UiHandler extends Handler {
private WeakReference<GiftV2View> mReference;

View File

@@ -1007,7 +1007,7 @@ public class MessageView extends FrameLayout {
setWishListComplete(chatRoomMessage, tvContent);
}
} else if (first == CUSTOM_MSG_PRIVILEGE) {
if (second == CustomAttachment.CUSTOM_MSG_PRIVILEGE_SECOND) {
if (second == CustomAttachment.CUSTOM_MSG_PRIVILEGE_SECOND || second == CustomAttachment.CUSTOM_MSG_PRIVILEGE_SECOND_VIDEO) {
setPrivilegeNoticeMessage(chatRoomMessage, tvContent);
}
} else {

View File

@@ -0,0 +1,189 @@
package com.nnbc123.app.avroom.widget
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.Keyframe
import android.animation.ObjectAnimator
import android.animation.PropertyValuesHolder
import android.graphics.Point
import android.net.Uri
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.view.isVisible
import com.chuhai.core.player.PlaybackState
import com.chuhai.core.player.PlayerListener
import com.chuhai.core.player.exo.ExoMediaItem
import com.chuhai.core.player.exo.ExoPlayer
import com.chuhai.utils.ICleared
import com.chuhai.utils.ktx.dp
import com.chuhai.utils.ktx.roundCorner
import com.chuhai.utils.log.ILog
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout
import com.nnbc123.app.ui.widget.magicindicator.buildins.UIUtil
import com.nnbc123.core.im.custom.bean.RoomPrivilegeAttachment
import java.util.LinkedList
/**
* Created by Max on 2023/11/3 10:18
* Desc:特权卡(播放引擎)
**/
class PrivilegeCardEngine(
private val parentView: ViewGroup,
private val viewWidth: Int,
private val viewHeight: Int,
) : ICleared, ILog, PlayerListener {
private val screenWidth: Int by lazy(LazyThreadSafetyMode.NONE) {
UIUtil.getScreenWidth(parentView.context)
}
private val screenHeight: Int by lazy(LazyThreadSafetyMode.NONE) {
UIUtil.getScreenHeight(parentView.context)
}
private val centerPoint by lazy(LazyThreadSafetyMode.NONE) {
Point(
screenWidth / 2,
screenHeight / 2
)
}
private val player: ExoPlayer by lazy {
ExoPlayer(parentView.context).apply {
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM
setListener(this@PrivilegeCardEngine)
val params: FrameLayout.LayoutParams = FrameLayout.LayoutParams(viewWidth, viewHeight)
this.layoutParams = params
params.leftMargin = centerPoint.x - viewWidth / 2
params.topMargin = screenHeight
if (parentView.indexOfChild(this) == -1) parentView.addView(this)
this.roundCorner(8.dp)
}
}
// 播放队列
private val queue: LinkedList<String> by lazy {
LinkedList()
}
/**
* 收到特权卡信令
*/
fun onPrivilegeSignaling(attachment: RoomPrivilegeAttachment) {
val url = attachment.effectUrl
if (attachment.cardType == 2 && !url.isNullOrEmpty()) {
addVideo(url)
}
}
private fun addVideo(url: String) {
queue.add(url)
loopQueue()
}
/**
* 轮训队列
*/
private fun loopQueue() {
if (queue.isEmpty()) {
return
}
if (!isPlayEnd()) {
// 当前还未播放结束
return
}
val source = queue.poll() ?: return
prepare(source)
}
private fun prepare(url: String) {
resetPlayer()
player.prepare(ExoMediaItem(Uri.parse(url)))
}
/**
* 当前播放器是否播放结束
*/
private fun isPlayEnd(): Boolean {
val state = player.getPlaybackState()
return state == PlaybackState.ENDED || state == PlaybackState.IDLE
}
override fun onPlaybackStateChanged(state: PlaybackState) {
super.onPlaybackStateChanged(state)
when (state) {
PlaybackState.READY -> {
startShowAnim {
player.setPlayWhenReady(true)
}
}
PlaybackState.ENDED, PlaybackState.IDLE -> {
startHideAnim {
loopQueue()
}
}
}
}
private fun startShowAnim(onEnd: () -> Unit) {
val keyTransY1 = Keyframe.ofFloat(0f, 0f)
val keyTransY2 =
Keyframe.ofFloat(1f, (centerPoint.y - screenHeight - viewHeight / 2).toFloat())
val keyScale1 = Keyframe.ofFloat(0f, 0f)
val keyScale2 = Keyframe.ofFloat(1f, 1f)
val p1 = PropertyValuesHolder.ofKeyframe("translationY", keyTransY1, keyTransY2)
val p2 = PropertyValuesHolder.ofKeyframe("scaleX", keyScale1, keyScale2)
val p3 = PropertyValuesHolder.ofKeyframe("scaleY", keyScale1, keyScale2)
val objectAnimator = ObjectAnimator.ofPropertyValuesHolder(player, p2, p3, p1)
objectAnimator.duration = 500
objectAnimator.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
onEnd.invoke()
}
})
player.isVisible = true
objectAnimator.start()
}
private fun startHideAnim(onEnd: () -> Unit) {
val keyTransY1 =
Keyframe.ofFloat(0f, (centerPoint.y - screenHeight - viewHeight / 2).toFloat())
val keyTransY2 = Keyframe.ofFloat(1f, 0f)
val keyScale1 = Keyframe.ofFloat(0f, 1f)
val keyScale2 = Keyframe.ofFloat(1f, 0f)
val p1 = PropertyValuesHolder.ofKeyframe("translationY", keyTransY1, keyTransY2)
val p2 = PropertyValuesHolder.ofKeyframe("scaleX", keyScale1, keyScale2)
val p3 = PropertyValuesHolder.ofKeyframe("scaleY", keyScale1, keyScale2)
val objectAnimator = ObjectAnimator.ofPropertyValuesHolder(player, p2, p3, p1)
objectAnimator.duration = 500
objectAnimator.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
onEnd.invoke()
}
})
objectAnimator.start()
}
private fun resetPlayer() {
player.stop()
player.clearAnimation()
player.translationY = 0f
player.translationX = 0f
player.alpha = 1f
player.scaleX = 0f
player.scaleY = 0f
player.isVisible = false
player.setPlayWhenReady(false)
}
override fun onCleared() {
super.onCleared()
queue.clear()
resetPlayer()
player.onCleared()
}
}

View File

@@ -856,6 +856,11 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
}
helper.setText(R.id.tv_name, item.getCardName());
helper.setText(R.id.tv_period_time, "有效期至:" + item.getExpireTime());
if (item.isVideoType() || item.isGiftType()) {
helper.setGone(R.id.iv_tag, true);
} else {
helper.setGone(R.id.iv_tag, false);
}
}
};
baseQuickAdapter.setOnItemClickListener((adapter, view, position) -> {

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/dp_8"
xmlns:tools="http://schemas.android.com/tools">
android:padding="@dimen/dp_8">
<com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/iv_pic"
@@ -12,31 +12,43 @@
android:layout_height="90dp"
android:scaleType="centerCrop"
android:src="@drawable/default_banner"
app:riv_corner_radius="@dimen/dp_8"
app:layout_constraintTop_toTopOf="parent"/>
app:layout_constraintTop_toTopOf="parent"
app:riv_corner_radius="@dimen/dp_8" />
<ImageView
android:id="@+id/iv_tag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginEnd="6dp"
android:src="@drawable/gift_panel_ic_privilege"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_period_time"
android:textSize="8sp"
android:textColor="@color/white_tran_80"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="有效期至2023-12-12"
android:layout_marginBottom="@dimen/dp_4"
android:textColor="@color/white_tran_80"
android:textSize="8sp"
app:layout_constraintBottom_toBottomOf="@+id/iv_pic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
app:layout_constraintStart_toStartOf="parent"
tools:text="有效期至2023-12-12" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_name"
android:textSize="@dimen/sp_10"
android:textColor="@color/color_white"
android:layout_marginTop="@dimen/dp_6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="至尊女神卡"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="@dimen/dp_6"
android:textColor="@color/color_white"
android:textSize="@dimen/sp_10"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/iv_pic"/>
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/iv_pic"
tools:text="至尊女神卡" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1428,7 +1428,7 @@ public final class IMNetEaseManager {
}
break;
case CUSTOM_MSG_PRIVILEGE:
if (customAttachment.getSecond() == CUSTOM_MSG_PRIVILEGE_SECOND) {
if (customAttachment.getSecond() == CUSTOM_MSG_PRIVILEGE_SECOND || customAttachment.getSecond() == CUSTOM_MSG_PRIVILEGE_SECOND_VIDEO) {
noticeRoomEvent(msg, RoomEvent.ROOM_PRIVILEGE);
addMessages(msg);
}

View File

@@ -26,5 +26,20 @@ data class GiftPrivilegeInfo(
val roomUid: Int = 0,
val uidStr: String = "",
val updateTime: String = "",
var isSelected: Boolean = false
) : Serializable
var isSelected: Boolean = false,
//卡片类型 0 图片 1 gif 2 mp4
var cardType: Int = 0,
// 时长毫秒
val duration: Long = 0,
// 特效视频url
val effectUrl: String? = null
) : Serializable {
fun isVideoType(): Boolean {
return cardType == 2
}
fun isGiftType(): Boolean {
return cardType == 1
}
}

View File

@@ -435,7 +435,8 @@ public class CustomAttachment implements MsgAttachment {
public static final int CUSTOM_MSG_SUB_kitchen_ALL_APP = 962; // 深海奇缘礼物全服飘屏通知
public static final int CUSTOM_MSG_PRIVILEGE = 102; //特权卡
public static final int CUSTOM_MSG_PRIVILEGE_SECOND = 1020;//特权卡
public static final int CUSTOM_MSG_PRIVILEGE_SECOND = 1020;//特权卡(图片、gif)
public static final int CUSTOM_MSG_PRIVILEGE_SECOND_VIDEO = 1021;//特权卡(视频类型)
public static final int CUSTOM_MSG_GAME_INVITE = 103;//发起邀请
public static final int CUSTOM_MSG_GAME_INVITE_SECOND = 1030;//发起邀请(发起用户)

View File

@@ -14,6 +14,43 @@ public class RoomPrivilegeAttachment extends CustomAttachment {
private long sendUid;
private int cardNum;
/**
* 下面3个字段 是1021新增的
*/
//卡片类型 0 图片 1 gif 2 mp4
private int cardType;
// 时长毫秒
private long duration;
// 特效视频url
private String effectUrl;
public int getCardType() {
return cardType;
}
public void setCardType(int cardType) {
this.cardType = cardType;
}
public long getDuration() {
return duration;
}
public void setDuration(long duration) {
this.duration = duration;
}
public String getEffectUrl() {
return effectUrl;
}
public void setEffectUrl(String effectUrl) {
this.effectUrl = effectUrl;
}
public RoomPrivilegeAttachment(int first, int second) {
super(first, second);
}
@@ -65,6 +102,16 @@ public class RoomPrivilegeAttachment extends CustomAttachment {
sendNick = jsonObject.getString("sendNick");
sendUid = jsonObject.getLong("sendUid");
cardNum = jsonObject.getInteger("cardNum");
if (jsonObject.containsKey("cardType")) {
cardType = jsonObject.getInteger("cardType");
}
if (jsonObject.containsKey("duration")) {
duration = jsonObject.getLong("duration");
}
if (jsonObject.containsKey("effectUrl")) {
effectUrl = jsonObject.getString("effectUrl");
}
}
@Override
@@ -80,6 +127,9 @@ public class RoomPrivilegeAttachment extends CustomAttachment {
", sendNick=" + sendNick +
", sendUid=" + sendUid +
", cardNum='" + cardNum + '\'' +
", cardType='" + cardType + '\'' +
", duration='" + duration + '\'' +
", effectUrl='" + effectUrl + '\'' +
'}';
}