完成涂鸦礼物功能

This commit is contained in:
huangjian
2022-08-23 18:00:22 +08:00
parent 41c57647ba
commit a13a7f684c
20 changed files with 529 additions and 245 deletions

View File

@@ -35,6 +35,7 @@ import com.yizhuan.erban.ui.utils.load
import com.yizhuan.erban.ui.utils.loadAnim
import com.yizhuan.erban.ui.widget.SimpleAnimListener
import com.yizhuan.erban.ui.widget.drawgift.DrawGiftHelper
import com.yizhuan.erban.ui.widget.drawgift.DrawGiftPlayHelper
import com.yizhuan.erban.utils.SpannableBuilder
import com.yizhuan.xchat_android_constants.XChatConstants
import com.yizhuan.xchat_android_core.auth.AuthModel
@@ -122,7 +123,7 @@ class RoomEffectView @JvmOverloads constructor(
private var isHideCarEffect = false
private val drawGiftHelper: DrawGiftHelper by lazy { DrawGiftHelper(context as Activity) }
private val drawGiftPlayHelper: DrawGiftPlayHelper by lazy { DrawGiftPlayHelper(context as Activity) }
private fun loopCarAnim() {
@@ -190,7 +191,7 @@ class RoomEffectView @JvmOverloads constructor(
val drawGiftAttachment =
(roomEvent.chatRoomMessage?.attachment as? DrawGiftAttachment)
?: return@subscribe
drawGiftHelper.prepareShowDrawGift(
drawGiftPlayHelper.prepareShowDrawGift(
drawGiftAttachment.giftId,
drawGiftAttachment.drawFixedArray,
false

View File

@@ -43,7 +43,7 @@ class CpGlobalDialog(context: Context) :
super.onStart()
window?.let {
it.attributes?.let { attr ->
attr.y = ScreenUtil.statusbarheight
attr.y = ScreenUtil.getStatusBarHeight(context)
attr.width = WindowManager.LayoutParams.MATCH_PARENT
attr.dimAmount = 0f
attr.height = ScreenUtil.dip2px(80f)

View File

@@ -4,6 +4,8 @@ import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Shader;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
@@ -34,6 +36,7 @@ import androidx.viewpager.widget.ViewPager;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.netease.nim.uikit.common.util.sys.ScreenUtil;
import com.trello.rxlifecycle3.components.support.RxAppCompatActivity;
import com.yizhuan.erban.BR;
import com.yizhuan.erban.R;
@@ -122,6 +125,7 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
private static final String TAG = "GiftDialog";
private static final int ITEM_TYPE_GOLD = 0; // 钻石
private static final int ITEM_TYPE_RADISH = 1; // 萝卜
private static final int MAX_DRAW_SIZE = 300;
public static String GIFT_DIALOG_FROM = ""; // 埋点用,标识从哪个位置打开弹框
private final Context context;
/**
@@ -178,7 +182,15 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
private List<List<GiftInfoVm>> pagerList;
private WalletInfo goldWalletInfo;
private int itemType = ITEM_TYPE_GOLD;
private View rlGifts;
private View llTabs;
private View llDrawGift;
private TextView tvDrawGiftTips;
private TextView tvDrawGiftChange;
private View ivDrawGiftRemoveLast;
private View ivDrawGiftRemoveAll;
private View ivDrawGiftClose;
private boolean isShowDrawGiftModel;
@Nullable
private DrawGiftHelper drawGiftHelper;
@@ -199,7 +211,7 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
* @param isHideMagicTab true则隐藏魔法默认false
*/
public GiftDialog(Context context, long OtherUid, boolean isInRoom, @Deprecated boolean isMagic, @Deprecated boolean isHideMagicTab, int giftId) {
super(context, R.style.ErbanBottomSheetDialogDimFalse);
super(context, R.style.ErbanBottomSheetDialog);
this.context = context;
this.uid = OtherUid;
this.giftId = giftId;
@@ -330,6 +342,7 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
WindowManager.LayoutParams params = getWindow().getAttributes();
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = WindowManager.LayoutParams.MATCH_PARENT;
params.dimAmount = 0f;
getWindow().setAttributes(params);
mSubscribe = IMNetEaseManager.get().getChatRoomEventObservable().subscribe(this::onReceiveRoomEvent);
}
@@ -362,6 +375,19 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
reloadView = root.findViewById(R.id.tv_reload);
reloadView.setOnClickListener(this);
loadingView = root.findViewById(R.id.iv_loading);
rlGifts = root.findViewById(R.id.rl_gifts);
llTabs = root.findViewById(R.id.ll_tabs);
llDrawGift = root.findViewById(R.id.ll_draw_gift);
tvDrawGiftTips = root.findViewById(R.id.tv_draw_gift_tips);
tvDrawGiftChange = root.findViewById(R.id.tv_draw_gift_change);
setGradient(tvDrawGiftChange);
ivDrawGiftRemoveLast = root.findViewById(R.id.iv_draw_gift_remove_last);
ivDrawGiftRemoveAll = root.findViewById(R.id.iv_draw_gift_remove_all);
ivDrawGiftClose = root.findViewById(R.id.iv_draw_gift_close);
ivDrawGiftClose.setOnClickListener(this);
ivDrawGiftRemoveLast.setOnClickListener(this);
ivDrawGiftRemoveAll.setOnClickListener(this);
tvDrawGiftChange.setOnClickListener(this);
showLoadingView();
showLoadingAnimation();
sendGiftButton.setOnClickListener(this);
@@ -396,6 +422,7 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
giftIndicator.showPosition(GiftIndicator.TYPE_LUCKY);
} else {
giftIndicator.hidePosition(GiftIndicator.TYPE_LUCKY);
giftIndicator.hidePosition(GiftIndicator.TYPE_DRAW_GIFT);
}
gridView = root.findViewById(R.id.gridView);
indicatorView = root.findViewById(R.id.indicator);
@@ -508,6 +535,18 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
}
private void setGradient(TextView textView) {
float endX = textView.getPaint().getTextSize() * textView.getText().length();
LinearGradient linearGradient = new LinearGradient(
0f, 0f, endX, 0f,
Color.parseColor("#57CF99"),
Color.parseColor("#33ECFF"),
Shader.TileMode.CLAMP
);
textView.getPaint().setShader(linearGradient);
textView.invalidate();
}
private void showLoadingAnimation() {
Animation rotateAnimation = new RotateAnimation(0, 360,
Animation.RELATIVE_TO_SELF, 0.5f,
@@ -584,21 +623,7 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
} else if (position == GiftIndicator.TYPE_WEEK) {
currentGiftInfoList = getWeekStarGiftInfos();
} else if (position == GiftIndicator.TYPE_DRAW_GIFT) {
currentGiftInfoList = getNormalGiftInfos();
if (drawGiftHelper == null) {
drawGiftHelper = new DrawGiftHelper((Activity) context);
}
drawGiftHelper.lazyDrawGiftView(mContentView.getHeight(), new DrawGiftView.DrawGiftListener() {
@Override
public void onGiftPainted(DrawGiftView drawGiftView, int giftId) {
}
@Override
public void onTouchEventUpWhenDrawDisable(DrawGiftView drawGiftView) {
dismiss();
}
});
currentGiftInfoList = getDrawGiftInfos();
}
// 有贵族礼物才显示贵族礼物的tab
if (ListUtils.isListEmpty(nobleGiftInfos)) {
@@ -614,9 +639,13 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
if (isKnap) {
tvGiftValue.setVisibility(View.VISIBLE);
showEmptyView();
} else if (position == GiftIndicator.TYPE_LUCKY || position == GiftIndicator.TYPE_WEEK) {
} else if (position == GiftIndicator.TYPE_LUCKY ||
position == GiftIndicator.TYPE_WEEK ||
position == GiftIndicator.TYPE_DRAW_GIFT) {
showEmptyView();
updateWeekStarDesc();
isShowDrawGiftModel = false;
updateDrawGift();
} else {
showLoadFailedView();
}
@@ -638,6 +667,7 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
}
updateLuckyBagIntro();
updateWeekStarDesc();
isShowDrawGiftModel = false;
updateDrawGift();
}
@@ -695,12 +725,83 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
}
private void updateDrawGift() {
if (drawGiftHelper == null || currentGiftInfo == null) return;
if (giftIndicator.getCurrrentType() == GiftIndicator.TYPE_DRAW_GIFT) {
drawGiftHelper.setCurrentGift(currentGiftInfo.getGiftId(), currentGiftInfo.getGiftUrl(), currentGiftInfo.getGoldPrice());
if (drawGiftHelper == null) {
drawGiftHelper = new DrawGiftHelper((Activity) context);
}
if (isShowDrawGiftModel &&
currentGiftInfo != null &&
giftIndicator.getCurrrentType() == GiftIndicator.TYPE_DRAW_GIFT) {
drawGiftHelper.lazyDrawGiftView(
ScreenUtil.dip2px(160) + ScreenUtil.getStatusBarHeight(context),
new DrawGiftView.DrawGiftListener() {
@Override
public void onReachMaxDrawSize() {
SingleToastUtil.showToast("一次最多赠送" + MAX_DRAW_SIZE + "个涂鸦礼物!");
}
@Override
public void onGiftPainted(DrawGiftView drawGiftView, int giftId) {
updateDrawGiftTips();
}
@Override
public void onTouchEventUpWhenDrawDisable(DrawGiftView drawGiftView) {
dismiss();
}
}
);
drawGiftHelper.setCurrentGift(
currentGiftInfo.getGiftId(),
currentGiftInfo.getGiftUrl(),
currentGiftInfo.getGoldPrice()
);
drawGiftHelper.setMaxDrawSize(MAX_DRAW_SIZE);
rlGifts.setVisibility(View.GONE);
llTabs.setVisibility(View.GONE);
llDrawGift.setVisibility(View.VISIBLE);
drawGiftHelper.setDrawEnable(true);
sendGiftButton.setEnabled(false);
WindowManager.LayoutParams params = getWindow().getAttributes();
if (params.dimAmount != 0.7f) {
params.dimAmount = 0.7f;
getWindow().setAttributes(params);
}
} else {
WindowManager.LayoutParams params = getWindow().getAttributes();
if (params.dimAmount != 0f) {
params.dimAmount = 0f;
getWindow().setAttributes(params);
}
rlGifts.setVisibility(View.VISIBLE);
llTabs.setVisibility(View.VISIBLE);
llDrawGift.setVisibility(View.GONE);
drawGiftHelper.setDrawEnable(false);
drawGiftHelper.resetDrawGiftView();
sendGiftButton.setEnabled(giftIndicator.getCurrrentType() != GiftIndicator.TYPE_DRAW_GIFT);
}
}
private void updateDrawGiftTips() {
if (drawGiftHelper == null) return;
if (drawGiftHelper.getDrawGiftSize() >= 10) {
int memberSize = 0;
if (!userOnMic && uid > 0) {
memberSize = 1;
} else if (avatarListAdapter != null && avatarListAdapter.getSelectedMember().size() > 0) {
memberSize = avatarListAdapter.getSelectedMember().size();
}
SpannableBuilder spannableBuilder = new SpannableBuilder();
spannableBuilder.append("已画出")
.append(String.valueOf(drawGiftHelper.getDrawGiftSize()), new ForegroundColorSpan(Color.parseColor("#FFBC51")))
.append("个,花费")
.append(String.valueOf(memberSize * drawGiftHelper.getTotalPrice()), new ForegroundColorSpan(Color.parseColor("#FFBC51")))
.append("钻石");
tvDrawGiftTips.setText(spannableBuilder.build());
sendGiftButton.setEnabled(true);
} else {
sendGiftButton.setEnabled(false);
tvDrawGiftTips.setText("至少画10个才能送出");
}
}
@@ -837,6 +938,7 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
setGoldOrRadishText(lastSelectedItem);
updateLuckyBagIntro();
updateWeekStarDesc();
isShowDrawGiftModel = true;
updateDrawGift();
});
container.addView(recyclerView);
@@ -907,6 +1009,12 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
GiftType.GIFT_TYPE_LUCKY);
}
private List<GiftInfo> getDrawGiftInfos() {
return GiftModel.get().getGiftInfosByType(
String.valueOf(AvRoomDataManager.get().getRoomUid()),
GiftType.GIFT_TYPE_DRAW_GIFT);
}
private List<GiftInfo> getNobleGiftInfos() {
return GiftModel.get().getGiftInfoList(GiftType.GIFT_TYPE_VIP);
}
@@ -953,6 +1061,7 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
break;
//送礼物
case R.id.btn_send:
final GiftInfo finalCurrentGiftInfo = currentGiftInfo;
sendGiftButton.setEnabled(false);
sendGiftButton.setText("赠送中...");
Log.e(TAG, "onClick: indicator type: " + giftIndicator.getCurrrentType());
@@ -962,7 +1071,7 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
sendGiftButton.setEnabled(true);
return;
}
if (currentGiftInfo == null || giftDialogBtnClickListener == null) {
if (finalCurrentGiftInfo == null || giftDialogBtnClickListener == null) {
sendGiftButton.setText("赠送");
sendGiftButton.setEnabled(true);
return;
@@ -980,9 +1089,9 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
targetUids.add(micMemberInfo);
Log.e(TAG, "onClick: indicator type: " + giftIndicator.getCurrrentType());
giftDialogBtnClickListener.onSendGiftBtnClick(
currentGiftInfo,
finalCurrentGiftInfo,
targetUids,
giftNumber == -1 ? currentGiftInfo.getCount() : giftNumber,
giftNumber == -1 ? finalCurrentGiftInfo.getCount() : giftNumber,
giftMessage,
giftIndicator.getCurrrentType() == GiftIndicator.TYPE_KNAP,
false,
@@ -990,10 +1099,7 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
new SenGiftCallback() {
@Override
public void onSuccess() {
if (sendGiftButton == null) return;
sendGiftButton.setText("赠送");
sendGiftButton.setEnabled(true);
clearDrawGift();
onSendGiftSuccess(finalCurrentGiftInfo);
}
@Override
@@ -1013,9 +1119,9 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
targetUids.add(micMemberInfo);
Log.e(TAG, "onClick: indicator type: " + giftIndicator.getCurrrentType());
giftDialogBtnClickListener.onSendGiftBtnClick(
currentGiftInfo,
finalCurrentGiftInfo,
targetUids,
giftNumber == -1 ? currentGiftInfo.getCount() : giftNumber,
giftNumber == -1 ? finalCurrentGiftInfo.getCount() : giftNumber,
giftMessage,
giftIndicator.getCurrrentType() == GiftIndicator.TYPE_KNAP,
false,
@@ -1023,10 +1129,7 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
new SenGiftCallback() {
@Override
public void onSuccess() {
if (sendGiftButton == null) return;
sendGiftButton.setText("赠送");
sendGiftButton.setEnabled(true);
clearDrawGift();
onSendGiftSuccess(finalCurrentGiftInfo);
}
@Override
@@ -1041,16 +1144,16 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
ArrayList<MicMemberInfo> selectedMembers = (ArrayList<MicMemberInfo>) avatarListAdapter.getSelectedMember();
if (giftIndicator.getCurrrentType() == GiftIndicator.TYPE_KNAP
&& giftNumber * selectedMembers.size() > currentGiftInfo.getCount()) {
&& giftNumber * selectedMembers.size() > finalCurrentGiftInfo.getCount()) {
SingleToastUtil.showToast("礼物数量不足");
sendGiftButton.setText("赠送");
sendGiftButton.setEnabled(true);
return;
}
giftDialogBtnClickListener.onSendGiftBtnClick(
currentGiftInfo,
finalCurrentGiftInfo,
selectedMembers,
giftNumber == -1 ? currentGiftInfo.getCount() : giftNumber,
giftNumber == -1 ? finalCurrentGiftInfo.getCount() : giftNumber,
giftMessage,
giftIndicator.getCurrrentType() == GiftIndicator.TYPE_KNAP,
avatarListAdapter.getSelectType() == GiftAvatarAdapter.SELECT_TYPE_WHOLE_MIC,
@@ -1058,10 +1161,7 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
new SenGiftCallback() {
@Override
public void onSuccess() {
if (sendGiftButton == null) return;
sendGiftButton.setText("赠送");
sendGiftButton.setEnabled(true);
clearDrawGift();
onSendGiftSuccess(finalCurrentGiftInfo);
}
@Override
@@ -1150,11 +1250,34 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
case R.id.ll_week_in:
DialogWebViewActivity.start(context, UriProvider.getWeekStarUrl(), true);
break;
case R.id.iv_draw_gift_close:
case R.id.tv_draw_gift_change:
clearDrawGift();
isShowDrawGiftModel = false;
updateDrawGift();
break;
case R.id.iv_draw_gift_remove_last:
if (drawGiftHelper != null) drawGiftHelper.removeLastStroke();
break;
case R.id.iv_draw_gift_remove_all:
clearDrawGift();
break;
default:
break;
}
}
private void onSendGiftSuccess(GiftInfo giftInfo) {
if (sendGiftButton == null) return;
sendGiftButton.setText("赠送");
sendGiftButton.setEnabled(true);
if (giftInfo.getGiftType() == GiftType.GIFT_TYPE_DRAW_GIFT) {
SingleToastUtil.showToast("发送涂鸦礼物:" + giftInfo.getGiftName() + "成功");
clearDrawGift();
dismiss();
}
}
private void reloadData(final boolean needShowLoading) {
if (needShowLoading) showLoadingView();
int currentType = giftIndicator.getCurrrentType();
@@ -1239,6 +1362,7 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
private void clearDrawGift() {
if (drawGiftHelper != null) {
tvDrawGiftTips.setText("至少画10个才能送出");
drawGiftHelper.clearDrawGift();
}
}
@@ -1304,13 +1428,14 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
@Override
public void onItemSelected(int position) {
avatarList.smoothScrollToPosition(position);
updateDrawGiftTips();
}
@Override
public void dismiss() {
super.dismiss();
if (drawGiftHelper != null) {
drawGiftHelper.onDialogDismiss();
drawGiftHelper.resetDrawGiftView();
}
}

View File

@@ -1,104 +1,31 @@
package com.yizhuan.erban.ui.widget.drawgift;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.FutureTarget;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import com.netease.nim.uikit.common.util.sys.ScreenUtil;
import com.netease.nim.uikit.support.glide.GlideApp;
import com.yizhuan.erban.R;
import com.yizhuan.xchat_android_core.gift.GiftModel;
import com.yizhuan.xchat_android_core.gift.bean.GiftInfo;
import com.yizhuan.xchat_android_library.utils.ListUtils;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
public class DrawGiftHelper {
//为了节省内存。通过giftId当做Key来缓存Bitmap如果你的giftId是String那么这里要修改成HashMap<String,Bitmap>
//其实这个东西你可以做成单例。我现在没用单例,就需要每次进入直播间都重新缓存
private final SparseArray<Bitmap> cacheBitmapByGiftIdMap;
private Activity activity;
private MyHandler handler;
private List<GiftInfo> giftBeanList;
//画礼物的背景View透明的并不是灰底
private final Activity activity;
private DrawGiftView drawGiftView;
//播放礼物动画的层
private DrawGiftPlayView playView;
//为了预加载里面存的是adapter的itemView你可以不用
private LinkedList<View> cachedItemViewList = new LinkedList<>();
private View cachedBottomGiftSheetView;
public DrawGiftHelper(Activity activity) {
this.activity = activity;
handler = new MyHandler(this);
//key是giftIdvalue是Bitmap。为了不重复生成Bitmap
cacheBitmapByGiftIdMap = new SparseArray<Bitmap>();
//本地的 giftBeanList你肯定是需要从缓存里取出来的至于什么时候刷新看你们的逻辑
giftBeanList = new ArrayList<GiftInfo>();
}
//播放礼物draw动画insertToFirst = 是否插入到队列前面
public void playDrawGift(List<DrawGiftModel> allDrawGiftArray, boolean insertToFirst) {
if (playView == null) {
playView = new DrawGiftPlayView(activity);
playView.setOnDrawAnimationListener(new DrawGiftPlayView.DrawAnimationListener() {
@Override
public void onAnimationNodeEnd(DrawGiftPlayView drawGiftPlayView) {
}
@Override
public void onAnimationAllOver(DrawGiftPlayView drawGiftPlayView) {
//动画放完了移除掉播放礼物View层。当然这里你也可以不移除一直保留
FrameLayout contentParent = (FrameLayout) activity.getWindow().getDecorView().findViewById(android.R.id.content);
contentParent.removeView(drawGiftPlayView);
}
});
}
if (playView.getParent() == null) {
//添加到decorView
FrameLayout contentParent = (FrameLayout) activity.getWindow().getDecorView().findViewById(android.R.id.content);
playView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
contentParent.addView(playView);
}
playView.addDrawGifts(allDrawGiftArray, insertToFirst);
}
//从缓存里取出bitmap
public Bitmap obtainThumbBitmap(int giftId, Bitmap largeBitmap) {
Bitmap thumbGiftBitmap = cacheBitmapByGiftIdMap.get(giftId);
if (thumbGiftBitmap == null) {
int newSize = ScreenUtil.dip2px(20);
thumbGiftBitmap = Bitmap.createScaledBitmap(largeBitmap, newSize, newSize, true);
cacheBitmapByGiftIdMap.put(giftId, thumbGiftBitmap);
}
return thumbGiftBitmap;
cacheBitmapByGiftIdMap = new SparseArray<>();
}
public void lazyDrawGiftView(int bottomSheetHeight, DrawGiftView.DrawGiftListener onDrawGiftListener) {
@@ -108,89 +35,11 @@ public class DrawGiftHelper {
drawGiftView.setDrawStrokeInterval(newSize);
drawGiftView.setOnDrawGiftListener(onDrawGiftListener);
drawGiftView.showInActivityWindow(activity, bottomSheetHeight);
drawGiftView.setPlaceHolderText("滑动手指,绘制图形");
}
}
public void onDialogDismiss() {
//底部弹框消失
//移除掉draw礼物View层。
//FrameLayout contentParent = (FrameLayout) getWindow().getDecorView().findViewById(android.R.id.content);
WindowManager mWindowManager = activity.getWindowManager();
mWindowManager.removeView(drawGiftView);
//如果不 = nullleakCanary会报内存泄漏但其实是误报
drawGiftView = null;
}
//计算需要的金币并setText
public void resetNeedPriceDisplay() {
float totalPrice = 0;
List<DrawGiftModel> allDrawGiftArray = drawGiftView.getAllDrawGiftArray();
for (DrawGiftModel giftModel : allDrawGiftArray) {
totalPrice += giftModel.getGiftPrice();
}
// giftSheetBuilder.costCoinTv.setText("消耗金币:"+totalPrice);
}
//子线程处理播放礼物的数据
public void prepareShowDrawGift(int giftId, List<List<Integer>> fixedArray, boolean insertToFirst) {
if (ListUtils.isListEmpty(fixedArray)) return;
//把服务器推送来的"礼物位置json" 和 本地的 giftBeanList 一一对应上找到礼物的bitmap
final List<DrawGiftModel> allDrawGiftArray = new ArrayList<>();
//经过测试这个子线程耗时仅为30ms左右(前提是bitmap已经被是从本地取的)
Thread thread = new Thread() {
@Override
public void run() {
//本机屏幕宽高
DisplayMetrics displayMetrics = new DisplayMetrics();
((WindowManager) activity.getApplicationContext().getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay().getMetrics(displayMetrics);
float viewWidth = displayMetrics.widthPixels;
float viewHeight = displayMetrics.heightPixels;
GiftInfo giftBean = GiftModel.get().findGiftInfoById(giftId);
Bitmap thumbGiftBitmap = cacheBitmapByGiftIdMap.get(giftId);
//fixedArray 是服务器推送过来的礼物json
for (List<Integer> fixedMap : fixedArray) {
//将服务器推送来的xy转成绝对像素坐标
DrawGiftModel drawGiftModel = new DrawGiftModel();
drawGiftModel.setX(fixedMap.get(0) / 1000f * viewWidth);
drawGiftModel.setY(fixedMap.get(1) / 1000f * viewHeight);
if (thumbGiftBitmap != null) {
//缓存中就有bitmap
drawGiftModel.setGiftBitmap(thumbGiftBitmap);
} else {
//缓存没有bitmap
//从Glide里找出礼物的bitmap
FutureTarget<Bitmap> futureBitmap = Glide.with(activity).asBitmap()
.load(giftBean.getGiftUrl())
.submit();
try {
Bitmap bitmap = futureBitmap.get();
thumbGiftBitmap = obtainThumbBitmap(giftId, bitmap);
drawGiftModel.setGiftBitmap(thumbGiftBitmap);
} catch (Exception e) {
e.printStackTrace();
//万一下载失败了,取本地的图片占位
Bitmap errorBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.default_cover);
drawGiftModel.setGiftBitmap(errorBitmap);
}
}
allDrawGiftArray.add(drawGiftModel);
}
Message message = Message.obtain(handler, 1, insertToFirst ? 1 : 0, 0, allDrawGiftArray);
handler.sendMessage(message);
}
};
thread.start();
}
public void setCurrentGift(int giftId, String giftUrl, float giftPrice) {
public void setCurrentGift(int giftId, String giftUrl, int giftPrice) {
if (drawGiftView == null) return;
GlideApp.with(activity)
.asBitmap()
@@ -206,7 +55,6 @@ public class DrawGiftHelper {
}
});
}
//是否可以画
@@ -216,11 +64,16 @@ public class DrawGiftHelper {
}
}
public List<List<Integer>> getDrawFixedArray() {
public void setMaxDrawSize(int maxDrawSize) {
if (drawGiftView != null) {
return drawGiftView.transformGiftArrayFitScreen(activity);
drawGiftView.setMaxDrawSize(maxDrawSize);
}
}
public void removeLastStroke() {
if (drawGiftView != null) {
drawGiftView.removeLastStroke();
}
return null;
}
public void clearDrawGift() {
@@ -229,27 +82,49 @@ public class DrawGiftHelper {
}
}
private static class MyHandler extends Handler {
private WeakReference<DrawGiftHelper> reference;
public MyHandler(DrawGiftHelper context) {
super(Looper.getMainLooper());
reference = new WeakReference<>(context);
@Nullable
public List<List<Integer>> getDrawFixedArray() {
if (drawGiftView != null) {
return drawGiftView.transformGiftArrayFitScreen(activity);
}
return null;
}
@Override
public void handleMessage(Message msg) {
final DrawGiftHelper activity = (DrawGiftHelper) reference.get();
if (activity == null) {
return;
}
if (msg.what == 1) {
List<DrawGiftModel> allDrawGiftArray = (List<DrawGiftModel>) msg.obj;
activity.playDrawGift(allDrawGiftArray, msg.arg1 == 1);
}
//计算需要的金币并setText
public int getTotalPrice() {
int totalPrice = 0;
List<DrawGiftModel> allDrawGiftArray = drawGiftView.getAllDrawGiftArray();
for (DrawGiftModel giftModel : allDrawGiftArray) {
totalPrice += giftModel.getGiftPrice();
}
return totalPrice;
}
public int getDrawGiftSize() {
return drawGiftView == null ? 0 : drawGiftView.getAllDrawGiftArray().size();
}
public void resetDrawGiftView() {
if (drawGiftView != null) {
//底部弹框消失
//移除掉draw礼物View层。
//FrameLayout contentParent = (FrameLayout) getWindow().getDecorView().findViewById(android.R.id.content);
WindowManager mWindowManager = activity.getWindowManager();
mWindowManager.removeView(drawGiftView);
//如果不 = nullleakCanary会报内存泄漏但其实是误报
drawGiftView = null;
}
}
//从缓存里取出bitmap
private Bitmap obtainThumbBitmap(int giftId, Bitmap largeBitmap) {
Bitmap thumbGiftBitmap = cacheBitmapByGiftIdMap.get(giftId);
if (thumbGiftBitmap == null) {
int newSize = ScreenUtil.dip2px(20);
thumbGiftBitmap = Bitmap.createScaledBitmap(largeBitmap, newSize, newSize, true);
cacheBitmapByGiftIdMap.put(giftId, thumbGiftBitmap);
}
return thumbGiftBitmap;
}
}

View File

@@ -8,7 +8,7 @@ public class DrawGiftModel {
private float x;
private float y;
private int giftId;
private float giftPrice;//礼物价格为了方便画的过程中快速的计算出当前一共画了多少钱的礼物默认0
private int giftPrice;//礼物价格为了方便画的过程中快速的计算出当前一共画了多少钱的礼物默认0
private Bitmap giftBitmap;
//在收到礼物显示动画的时候本demo为了体现出礼物放大消失的动画引入了这个Matrix参数如果没有放大动画就不需要这两个
@@ -57,11 +57,11 @@ public class DrawGiftModel {
this.matrix = matrix;
}
public float getGiftPrice() {
public int getGiftPrice() {
return giftPrice;
}
public void setGiftPrice(float giftPrice) {
public void setGiftPrice(int giftPrice) {
this.giftPrice = giftPrice;
}
}

View File

@@ -0,0 +1,165 @@
package com.yizhuan.erban.ui.widget.drawgift;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.SparseArray;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.FutureTarget;
import com.netease.nim.uikit.common.util.sys.ScreenUtil;
import com.yizhuan.erban.R;
import com.yizhuan.xchat_android_core.gift.GiftModel;
import com.yizhuan.xchat_android_core.gift.bean.GiftInfo;
import com.yizhuan.xchat_android_library.utils.ListUtils;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
public class DrawGiftPlayHelper {
//为了节省内存。通过giftId当做Key来缓存Bitmap如果你的giftId是String那么这里要修改成HashMap<String,Bitmap>
//其实这个东西你可以做成单例。我现在没用单例,就需要每次进入直播间都重新缓存
private final SparseArray<Bitmap> cacheBitmapByGiftIdMap;
private final Activity activity;
private MyHandler handler;
//播放礼物动画的层
private DrawGiftPlayView playView;
public DrawGiftPlayHelper(Activity activity) {
this.activity = activity;
cacheBitmapByGiftIdMap = new SparseArray<>();
}
//播放礼物draw动画insertToFirst = 是否插入到队列前面
public void playDrawGift(List<DrawGiftModel> allDrawGiftArray, boolean insertToFirst) {
if (playView == null) {
playView = new DrawGiftPlayView(activity);
playView.setOnDrawAnimationListener(new DrawGiftPlayView.DrawAnimationListener() {
@Override
public void onAnimationNodeEnd(DrawGiftPlayView drawGiftPlayView) {
}
@Override
public void onAnimationAllOver(DrawGiftPlayView drawGiftPlayView) {
//动画放完了移除掉播放礼物View层。当然这里你也可以不移除一直保留
FrameLayout contentParent = (FrameLayout) activity.getWindow().getDecorView().findViewById(android.R.id.content);
contentParent.removeView(drawGiftPlayView);
}
});
}
if (playView.getParent() == null) {
//添加到decorView
FrameLayout contentParent = (FrameLayout) activity.getWindow().getDecorView().findViewById(android.R.id.content);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
layoutParams.topMargin = ScreenUtil.getStatusBarHeight(activity);
playView.setLayoutParams(layoutParams);
contentParent.addView(playView);
}
playView.addDrawGifts(allDrawGiftArray, insertToFirst);
}
//子线程处理播放礼物的数据
public void prepareShowDrawGift(int giftId, List<List<Integer>> fixedArray, boolean insertToFirst) {
if (ListUtils.isListEmpty(fixedArray)) return;
//把服务器推送来的"礼物位置json" 和 本地的 giftBeanList 一一对应上找到礼物的bitmap
final List<DrawGiftModel> allDrawGiftArray = new ArrayList<>();
//经过测试这个子线程耗时仅为30ms左右(前提是bitmap已经被是从本地取的)
Thread thread = new Thread() {
@Override
public void run() {
//本机屏幕宽高
DisplayMetrics displayMetrics = new DisplayMetrics();
((WindowManager) activity.getApplicationContext().getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay().getMetrics(displayMetrics);
float viewWidth = displayMetrics.widthPixels;
float viewHeight = displayMetrics.heightPixels;
GiftInfo giftBean = GiftModel.get().findGiftInfoById(giftId);
Bitmap thumbGiftBitmap = cacheBitmapByGiftIdMap.get(giftId);
//fixedArray 是服务器推送过来的礼物json
for (List<Integer> fixedMap : fixedArray) {
//将服务器推送来的xy转成绝对像素坐标
DrawGiftModel drawGiftModel = new DrawGiftModel();
drawGiftModel.setX(fixedMap.get(0) / 1000f * viewWidth);
drawGiftModel.setY(fixedMap.get(1) / 1000f * viewHeight);
if (thumbGiftBitmap != null) {
//缓存中就有bitmap
drawGiftModel.setGiftBitmap(thumbGiftBitmap);
} else {
//缓存没有bitmap
//从Glide里找出礼物的bitmap
FutureTarget<Bitmap> futureBitmap = Glide.with(activity).asBitmap()
.load(giftBean.getGiftUrl())
.submit();
try {
Bitmap bitmap = futureBitmap.get();
thumbGiftBitmap = obtainThumbBitmap(giftId, bitmap);
drawGiftModel.setGiftBitmap(thumbGiftBitmap);
} catch (Exception e) {
e.printStackTrace();
//万一下载失败了,取本地的图片占位
Bitmap errorBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.default_cover);
drawGiftModel.setGiftBitmap(errorBitmap);
}
}
allDrawGiftArray.add(drawGiftModel);
}
if (handler == null) handler = new MyHandler(DrawGiftPlayHelper.this);
Message message = Message.obtain(handler, 1, insertToFirst ? 1 : 0, 0, allDrawGiftArray);
handler.sendMessage(message);
}
};
thread.start();
}
//从缓存里取出bitmap
private Bitmap obtainThumbBitmap(int giftId, Bitmap largeBitmap) {
Bitmap thumbGiftBitmap = cacheBitmapByGiftIdMap.get(giftId);
if (thumbGiftBitmap == null) {
int newSize = ScreenUtil.dip2px(20);
thumbGiftBitmap = Bitmap.createScaledBitmap(largeBitmap, newSize, newSize, true);
cacheBitmapByGiftIdMap.put(giftId, thumbGiftBitmap);
}
return thumbGiftBitmap;
}
private static class MyHandler extends Handler {
private final WeakReference<DrawGiftPlayHelper> reference;
public MyHandler(DrawGiftPlayHelper context) {
super(Looper.getMainLooper());
reference = new WeakReference<>(context);
}
@Override
public void handleMessage(Message msg) {
final DrawGiftPlayHelper activity = (DrawGiftPlayHelper) reference.get();
if (activity == null) {
return;
}
if (msg.what == 1) {
List<DrawGiftModel> allDrawGiftArray = (List<DrawGiftModel>) msg.obj;
activity.playDrawGift(allDrawGiftArray, msg.arg1 == 1);
}
}
}
}

View File

@@ -16,7 +16,7 @@ import java.util.List;
public class DrawGiftPlayView extends View {
//需要被画上的全部的礼物采用链表的方式每次取第0个
private LinkedList<List<DrawGiftModel>> allDrawGiftsLinkedList;
private final LinkedList<List<DrawGiftModel>> allDrawGiftsLinkedList;
//当前这幅画播放到第几个礼物
private int currentGiftShowIndex;

View File

@@ -19,7 +19,6 @@ import android.view.WindowManager;
import com.yizhuan.erban.R;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
//手绘礼物的View
@@ -37,13 +36,16 @@ public class DrawGiftView extends View {
//当前选中的礼物的id和bitmap
private int currentGiftId;
private Bitmap currentGiftBitmap;
private float currentGiftPrice;
private int currentGiftPrice;
//连续两个礼物之间的间距像素0表示用当前礼物的宽
private int drawStrokeInterval;
//是否可以画
private boolean drawEnable = false;
//没画的时候,显示的默认文本
private String placeHolderText = "涂鸦模式,绘制你的图案";
private int maxDrawSize = 300;
//一次触摸事件只调用一次onReachMaxDrawSize
private boolean isCallMaxDrawSize;
public DrawGiftView(Context context) {
@@ -78,7 +80,7 @@ public class DrawGiftView extends View {
textPaint.setTextSize(42);
textPaint.setTextAlign(Paint.Align.CENTER);
if (placeHolderText != null) {
float baseline = (getHeight() - placeHolderViewHeight) / 2 + 340;
float baseline = (getHeight() - placeHolderViewHeight) / 2 + 210;
canvas.drawText(placeHolderText, getWidth() / 2f, baseline, textPaint);
}
} else {
@@ -100,6 +102,15 @@ public class DrawGiftView extends View {
//不允许画 || 当前没选中任何礼物
return super.onTouchEvent(event);
}
isCallMaxDrawSize = false;
if (allDrawGiftArray.size() >= maxDrawSize) {
if (onDrawGiftListener != null) {
isCallMaxDrawSize = true;
onDrawGiftListener.onReachMaxDrawSize();
}
return super.onTouchEvent(event);
}
//点下
mLastX = checkIfBelongHorizontalEdge(event.getX());
mLastY = checkIfBelongVerticalEdge(event.getY());
@@ -108,13 +119,19 @@ public class DrawGiftView extends View {
//记录这一笔的开头
strokeFirstPositionArray.add(allDrawGiftArray.size() - 1);
return true;
case MotionEvent.ACTION_MOVE:
if (!drawEnable || currentGiftBitmap == null) {
//不允许画 || 当前没选中任何礼物
return super.onTouchEvent(event);
}
if (allDrawGiftArray.size() >= maxDrawSize) {
if (onDrawGiftListener != null && !isCallMaxDrawSize) {
isCallMaxDrawSize = true;
onDrawGiftListener.onReachMaxDrawSize();
}
return super.onTouchEvent(event);
}
float moveX = checkIfBelongHorizontalEdge(event.getX());
float moveY = checkIfBelongVerticalEdge(event.getY());
@@ -216,7 +233,7 @@ public class DrawGiftView extends View {
}
//设置当前这笔礼物
public void setCurrentGift(int giftId, Bitmap giftBitmap, float giftPrice) {
public void setCurrentGift(int giftId, Bitmap giftBitmap, int giftPrice) {
this.currentGiftId = giftId;
this.currentGiftBitmap = giftBitmap;
this.currentGiftPrice = giftPrice;
@@ -239,6 +256,7 @@ public class DrawGiftView extends View {
wl.height = activity.getWindow().getDecorView().findViewById(android.R.id.content).getHeight() - bottomSheetHeight;
wl.token = activity.getWindow().getAttributes().token;
wl.format = PixelFormat.TRANSLUCENT;//Toast就是用这个实现的透明
//wl.alpha = 0.7f;
mWindowManager.addView(this, wl);
}
@@ -298,6 +316,10 @@ public class DrawGiftView extends View {
invalidate();
}
public void setMaxDrawSize(int maxDrawSize) {
this.maxDrawSize = maxDrawSize;
}
//是否可以画
public void setDrawEnable(boolean drawEnable) {
if (drawEnable != this.drawEnable) {
@@ -315,6 +337,9 @@ public class DrawGiftView extends View {
}
public interface DrawGiftListener {
void onReachMaxDrawSize();
//新的礼物节点被画上
public void onGiftPainted(DrawGiftView drawGiftView, int giftId);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white_tran_20" />
<corners
android:bottomLeftRadius="0dp"
android:bottomRightRadius="0dp"
android:topLeftRadius="8dp"
android:topRightRadius="8dp" />
</shape>

View File

@@ -8,7 +8,63 @@
android:background="@drawable/bg_dialog_room_operation"
android:orientation="vertical">
<LinearLayout
android:id="@+id/ll_draw_gift"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginBottom="10dp"
android:background="@drawable/bg_draw_gift_operation"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_draw_gift_tips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:text="至少画10个才能送出"
android:textColor="@color/white"
android:textSize="14sp" />
<View
android:layout_width="0dp"
android:layout_height="1px"
android:layout_weight="1" />
<TextView
android:id="@+id/tv_draw_gift_change"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:text="切换涂鸦"
android:textColor="@color/white"
android:textSize="12sp" />
<ImageView
android:id="@+id/iv_draw_gift_remove_last"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:src="@drawable/ic_draw_gift_remove_last" />
<ImageView
android:id="@+id/iv_draw_gift_remove_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:src="@drawable/ic_draw_gift_remove_all" />
<ImageView
android:id="@+id/iv_draw_gift_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="15dp"
android:src="@drawable/ic_draw_gift_close" />
</LinearLayout>
<RelativeLayout
android:id="@+id/rl_avatars"
android:layout_width="match_parent"
android:layout_height="55dp">
@@ -137,6 +193,7 @@
</LinearLayout>
<RelativeLayout
android:id="@+id/rl_gifts"
android:layout_width="match_parent"
android:layout_height="222dp"
android:layout_marginTop="@dimen/dp_10">
@@ -358,7 +415,7 @@
android:textSize="@dimen/dp_14"
android:visibility="gone"
tools:ignore="SpUsage"
tools:visibility="visible" />
tools:visibility="gone" />
<RelativeLayout
android:id="@+id/layout_recharge"
@@ -391,7 +448,6 @@
android:visibility="gone"
tools:visibility="visible" />
<TextView
android:id="@+id/tv_text_gold"
android:layout_width="wrap_content"

View File

@@ -48,6 +48,7 @@
<!--意思是白色 60%透明度-->
<color name="white_op_30">#B3FFFFFF</color>
<color name="white_tran_10">#19FFFFFF</color>
<color name="white_tran_20">#33FFFFFF</color>
<color name="white_transparent_12">#1EFFFFFF</color>
<color name="white_transparent_14">#23FFFFFF</color>

Binary file not shown.

After

Width:  |  Height:  |  Size: 826 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 966 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 976 B