1:添加cp进场动画效果

2:修改cp礼物弹框
3:添加组成cp后进入心动空间跳转
This commit is contained in:
2025-11-24 18:48:14 +08:00
parent a1e123f0bf
commit 0dd7c367cb
13 changed files with 1334 additions and 475 deletions

View File

@@ -4534,8 +4534,7 @@ public class RetrofitClient {
});
}
public void roomUserCharmList(String room_id, String
user_id, BaseObserver<List<RoomUserCharmListBean>> observer) {
public void roomUserCharmList(String room_id, String user_id, BaseObserver<List<RoomUserCharmListBean>> observer) {
sApiServer.roomUserCharmList(room_id, user_id).enqueue(new Callback<BaseModel<List<RoomUserCharmListBean>>>() {
@Override
public void onResponse(Call<BaseModel<List<RoomUserCharmListBean>>> call, Response<BaseModel<List<RoomUserCharmListBean>>> response) {
@@ -4566,7 +4565,8 @@ public class RetrofitClient {
if (baseModel.getCode() == 1) {
observer.onNext(baseModel.getData());
} else if (baseModel.getCode() == 0) {
observer.onNext(null);
ToastUtils.showLong(baseModel.getMsg());
// observer.onNext(null);
}
}
}

View File

@@ -0,0 +1,919 @@
package com.xscm.moduleutil.utils.roomview;
import android.content.Context;
import android.os.AsyncTask;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.blankj.utilcode.util.LogUtils;
import com.makeramen.roundedimageview.RoundedImageView;
import com.tencent.qgame.animplayer.AnimConfig;
import com.tencent.qgame.animplayer.AnimView;
import com.tencent.qgame.animplayer.inter.IAnimListener;
import com.xscm.moduleutil.R;
import com.xscm.moduleutil.utils.ImageUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
/**
* 项目名称:羽声语音
* 时间2025/11/24 9:50
* 用途:
*/
public class RoomCPView extends FrameLayout {
private AnimView anim_cp;
private boolean isLoadEffect = false;
private boolean isShow = true; // 是否开启特效
private ReentrantLock lock = new ReentrantLock();
private List<String> animationArray = new ArrayList<>();
public ExecutorService queue = Executors.newSingleThreadExecutor();
private Context mContext;
private boolean isOnece;
private RoundedImageView room_cp_head1;
private RoundedImageView room_cp_head2;
private TextView room_cp_name1, room_cp_name2;
private LinearLayout avatarContainer1;
private ConstraintLayout avatarsParentContainer;
// 动画队列和锁机制
private final Queue<AnimationTask> animationQueue = new LinkedList<>();
private boolean isAnimationRunning = false;
private final Object animationLock = new Object();
// 下载任务缓存
private final Queue<DownloadTask> downloadQueue = new LinkedList<>();
private boolean isDownloadRunning = false;
private final Object downloadLock = new Object();
private String currPlayPath = "";
public void setQueue(ExecutorService queue) {
this.queue = queue;
}
public RoomCPView(@NonNull Context context) {
super(context);
this.mContext = context;
init();
}
public RoomCPView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
init();
}
public RoomCPView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
init();
}
public RoomCPView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
this.mContext = context;
init();
}
private void init() {
isLoadEffect = false;
initView();
// 设置动画监听器
setupAnimListener();
}
/**
* 设置动画监听器
*/
private void setupAnimListener() {
if (anim_cp != null) {
anim_cp.setAnimListener(new IAnimListener() {
@Override
public void onVideoDestroy() {
LogUtils.e("onVideoDestroy");
}
@Override
public void onVideoComplete() {
LogUtils.e("onVideoComplete");
// 确保所有UI操作在主线程中执行
post(() -> {
if (anim_cp != null) {
// 停止头像动画
stopAvatarAnimation();
// 隐藏动画视图和头像
anim_cp.setVisibility(View.GONE);
avatarContainer1.setVisibility(View.GONE);
if (isOnece) {
return;
}
// 通知播放完成
notifyPlaybackComplete();
loadStartAnimation();
}
});
}
@Override
public void onVideoRender(int i, @Nullable AnimConfig animConfig) {
// LogUtils.e("onVideoRender", i, animConfig);
}
@Override
public void onVideoStart() {
LogUtils.e("onVideoStart");
// 确保所有UI操作在主线程中执行
post(() -> {
// 动画开始,显示视图和头像
setVisibility(View.VISIBLE);
anim_cp.setVisibility(View.VISIBLE);
avatarContainer1.setVisibility(View.VISIBLE);
// 启动头像上下浮动动画
// startAvatarFloatAnimation();
});
}
@Override
public boolean onVideoConfigReady(@NonNull AnimConfig animConfig) {
LogUtils.e("onVideoConfigReady", animConfig);
return true;
}
@Override
public void onFailed(int i, @Nullable String s) {
LogUtils.e("onFailed", s);
// 确保所有UI操作在主线程中执行
post(() -> {
// 动画失败,隐藏视图
setVisibility(View.GONE);
anim_cp.setVisibility(View.GONE);
// 继续播放下一个
loadStartAnimation();
});
}
});
}
}
private void initView() {
LayoutInflater.from(getContext()).inflate(R.layout.room_cp_vip_view, this, true);
anim_cp = findViewById(R.id.anim_cp);
room_cp_head1 = findViewById(R.id.room_cp_head1);
room_cp_head2 = findViewById(R.id.room_cp_head2);
room_cp_name1 = findViewById(R.id.room_cp_name1);
room_cp_name2 = findViewById(R.id.room_cp_name2);
// 获取头像的父布局
avatarContainer1 = findViewById(R.id.ll_head);
// 获取包含两个头像的父 LinearLayout
avatarsParentContainer = (ConstraintLayout) avatarContainer1.getParent();
// // 初始状态隐藏头像和名称
// room_cp_head1.setVisibility(View.GONE);
// room_cp_head2.setVisibility(View.GONE);
// room_cp_name1.setVisibility(View.GONE);
// room_cp_name2.setVisibility(View.GONE);
}
public void setCPTextData(String room_head1, String room_head2, String room_cp_name1, String room_cp_name2) {
ImageUtils.loadHead(room_head1, room_cp_head1);
ImageUtils.loadHead(room_head2, room_cp_head2);
this.room_cp_name1.setText(room_cp_name1);
this.room_cp_name2.setText(room_cp_name2);
}
private void loadStartAnimation() {
if (!isShow) {
// isshow 为是否开启特效 如果未开启则return
return;
}
String animationPath = null;
// list加锁
lock.lock();
try {
// 如果list长度大于0
if (!animationArray.isEmpty()) {
// 动画路径则赋值取list中的第一个数据
animationPath = animationArray.get(0);
// 移除list的第一条数据
animationArray.remove(0);
isLoadEffect = true;
} else {
isLoadEffect = false;
// 队列为空,释放资源但不销毁视图
post(() -> {
destroyEffectView();
});
}
} finally {
// 解锁
lock.unlock();
}
if (isLoadEffect && animationPath != null && !TextUtils.isEmpty(animationPath)) {
String finalAnimationPath = animationPath;
post(new Runnable() {
@Override
public void run() {
// 处理MP4动画文件可能是网络URL
handleMP4File(finalAnimationPath, new DownloadCallback() {
@Override
public void onSuccess(String localPath) {
post(() -> {
// 设置MP4动画文件
currPlayPath = localPath;
// 启动从底部弹起动画
startBottomUpAnimation();
// 开始播放动画
anim_cp.setLoop(1);
});
}
@Override
public void onError(String error) {
LogUtils.e("MP4下载或播放失败: " + error);
// 处理失败情况,继续播放下一个
post(() -> {
lock.lock();
try {
isLoadEffect = false;
} finally {
lock.unlock();
}
loadStartAnimation();
});
}
});
}
});
}
}
/**
* CP特效进来
* @param room_head1 头像1
* @param room_head2 头像2
* @param room_name1 名称1
* @param room_name2 名称2
* @param mp4Path MP4动画文件路径
*/
public void displayEffectView(String room_head1, String room_head2, String room_name1, String room_name2, String mp4Path) {
// 确保视图已初始化
reinitView();
// 设置CP数据但不显示头像
setCPTextData(room_head1, room_head2, room_name1, room_name2);
// 确保头像初始为隐藏状态
// room_cp_head1.setVisibility(View.GONE);
// room_cp_head2.setVisibility(View.GONE);
// room_cp_name1.setVisibility(View.GONE);
// room_cp_name2.setVisibility(View.GONE);
// 确保视图可见
setVisibility(View.VISIBLE);
// 检查队列是否已初始化
if (queue == null) {
queue = Executors.newSingleThreadExecutor();
}
queue.execute(new Runnable() {
@Override
public void run() {
// 如果mp4Path不存在return
if (mp4Path == null || mp4Path.isEmpty()) {
return;
}
// 将mp4Path链接转为小写
String playImage = mp4Path;
String pathExtension = getFileExtension(playImage).toLowerCase();
// 判定礼物的后缀是否为svga或者mp4如果非这两种 则return
if (!("svga".equals(pathExtension) || "mp4".equals(pathExtension))) {
return;
}
// 锁住list
lock.lock();
try {
// 添加动画数据进list
animationArray.add(playImage);
// 如果没有在加载则开始加载
if (!isLoadEffect) {
// 更改加载状态标记
isLoadEffect = true;
loadStartAnimation();
}
} finally {
// 解锁
lock.unlock();
}
}
});
}
/**
* 原始的动画方法,现在只被内部调用
*/
public void startAnimation(AnimationListener listener) {
// 设置进入动画
AlphaAnimation fadeIn = new AlphaAnimation(0f, 1f);
fadeIn.setDuration(500);
fadeIn.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {
// 保持显示1秒后开始退出动画
postDelayed(() -> {
AlphaAnimation fadeOut = new AlphaAnimation(1f, 0f);
fadeOut.setDuration(500);
fadeOut.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {
if (listener != null) {
listener.onAnimationEnd();
}
}
@Override
public void onAnimationRepeat(Animation animation) {}
});
startAnimation(fadeOut);
}, 1000);
}
@Override
public void onAnimationRepeat(Animation animation) {}
});
startAnimation(fadeIn);
}
public interface AnimationListener {
void onAnimationEnd();
}
// 添加播放完成监听接口
public interface OnPlaybackCompleteListener {
void onPlaybackComplete();
}
// 添加成员变量
private List<OnPlaybackCompleteListener> playbackCompleteListeners = new ArrayList<>();
// 添加监听器管理方法
public void addOnPlaybackCompleteListener(OnPlaybackCompleteListener listener) {
if (listener != null && !playbackCompleteListeners.contains(listener)) {
playbackCompleteListeners.add(listener);
}
}
public void removeOnPlaybackCompleteListener(OnPlaybackCompleteListener listener) {
if (listener != null) {
playbackCompleteListeners.remove(listener);
}
}
public void clearPlaybackCompleteListeners() {
playbackCompleteListeners.clear();
}
// 触发播放完成回调的方法
private void notifyPlaybackComplete() {
for (OnPlaybackCompleteListener listener : new ArrayList<>(playbackCompleteListeners)) {
if (listener != null) {
listener.onPlaybackComplete();
}
}
}
/**
* 动画任务类,用于存储动画所需的数据
*/
public static class AnimationTask {
String room_head1;
String room_head2;
String room_cp_name1;
String room_cp_name2;
String mp4Path; // MP4动画文件路径
AnimationListener listener;
AnimationTask(String room_head1, String room_head2, String room_cp_name1, String room_cp_name2, String mp4Path, AnimationListener listener) {
this.room_head1 = room_head1;
this.room_head2 = room_head2;
this.room_cp_name1 = room_cp_name1;
this.room_cp_name2 = room_cp_name2;
this.mp4Path = mp4Path;
this.listener = listener;
}
}
/**
* 处理MP4文件如果是网络URL则下载到本地
* @param path 文件路径或URL
* @param callback 下载回调
*/
private void handleMP4File(String path, DownloadCallback callback) {
// 判断是否是网络URL
if (path != null && (path.startsWith("http://") || path.startsWith("https://"))) {
// 是网络URL需要下载
downloadFile(path, callback);
} else {
// 本地路径,直接使用
if (callback != null) {
callback.onSuccess(path);
}
}
}
/**
* 下载文件到本地
* @param url 下载URL
* @param callback 下载回调
*/
private void downloadFile(String url, DownloadCallback callback) {
synchronized (downloadLock) {
// 创建下载任务并加入队列
DownloadTask task = new DownloadTask(url, callback);
downloadQueue.offer(task);
// 如果当前没有下载任务在执行,则开始下载
if (!isDownloadRunning) {
processNextDownload();
}
}
}
/**
* 处理下一个下载任务
*/
private void processNextDownload() {
synchronized (downloadLock) {
if (downloadQueue.isEmpty()) {
isDownloadRunning = false;
return;
}
isDownloadRunning = true;
DownloadTask currentTask = downloadQueue.poll();
// 执行下载任务
new DownloadAsyncTask(currentTask.callback).execute(currentTask.url);
}
}
/**
* 异步下载任务
*/
private class DownloadAsyncTask extends AsyncTask<String, Void, String> {
private DownloadCallback callback;
private String errorMessage;
public DownloadAsyncTask(DownloadCallback callback) {
this.callback = callback;
}
@Override
protected String doInBackground(String... urls) {
String url = urls[0];
try {
// 获取文件名
int lastSlashIndex = url.lastIndexOf('/');
String fileName = lastSlashIndex != -1 ? url.substring(lastSlashIndex + 1) : url;
int queryIndex = fileName.indexOf("?");
if (queryIndex != -1) {
fileName = fileName.substring(0, queryIndex);
}
// 创建本地文件
File dir = new File(getContext().getCacheDir(), "animations");
if (!dir.exists()) {
dir.mkdirs();
}
File file = new File(dir, fileName);
// 如果文件已存在,直接返回本地路径
if (file.exists()) {
return file.getAbsolutePath();
}
// 下载文件
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
errorMessage = "服务器返回HTTP错误代码: " + connection.getResponseCode();
return null;
}
InputStream input = connection.getInputStream();
FileOutputStream output = new FileOutputStream(file);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = input.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
output.close();
input.close();
connection.disconnect();
return file.getAbsolutePath();
} catch (IOException e) {
errorMessage = "下载失败: " + e.getMessage();
return null;
}
}
@Override
protected void onPostExecute(String result) {
synchronized (downloadLock) {
// 下载完成,处理下一个下载任务
processNextDownload();
}
// 通知回调
if (callback != null) {
if (result != null) {
callback.onSuccess(result);
} else {
callback.onError(errorMessage != null ? errorMessage : "未知错误");
}
}
}
}
/**
* 下载任务类
*/
private static class DownloadTask {
String url;
DownloadCallback callback;
DownloadTask(String url, DownloadCallback callback) {
this.url = url;
this.callback = callback;
}
}
/**
* 下载回调接口
*/
private interface DownloadCallback {
void onSuccess(String localPath);
void onError(String error);
}
/**
* 获取文件扩展名
* @param url 文件URL
* @return 文件扩展名
*/
private String getFileExtension(String url) {
if (url != null && url.contains(".")) {
return url.substring(url.lastIndexOf(".") + 1);
}
return "";
}
/**
* 销毁特效视图
*/
public void destroyEffectView() {
// 停止头像动画
stopAvatarAnimation();
// 清理监听器
clearPlaybackCompleteListeners();
// 停止动画视图但保留组件以便重用
if (anim_cp != null) {
anim_cp.stopPlay();
anim_cp.setVisibility(View.GONE);
}
// 隐藏视图但不移除,以便再次使用
setVisibility(View.GONE);
// 清空动画队列
lock.lock();
try {
animationArray.clear();
isLoadEffect = false;
} finally {
lock.unlock();
}
}
/**
* 从底部弹起动画
*/
private void startBottomUpAnimation() {
// 获取父视图的高度如果为0则使用屏幕高度
float parentHeight = 0;
if (getParent() != null) {
parentHeight = ((View) getParent()).getHeight();
}
if (parentHeight <= 0) {
parentHeight = getResources().getDisplayMetrics().heightPixels;
}
// 设置初始位置在屏幕底部外
// setTranslationY(parentHeight);
// 创建从底部弹起的动画
TranslateAnimation bottomUpAnimation = new TranslateAnimation(
Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 0,
Animation.RELATIVE_TO_PARENT, 1.0f, Animation.RELATIVE_TO_PARENT, 0.0f);
bottomUpAnimation.setDuration(2000); // 动画持续时间
// 创建弹性插值器
Interpolator overshootInterpolator = new OvershootInterpolator(0.5f);
bottomUpAnimation.setInterpolator(overshootInterpolator);
// 应用动画
startAnimation(bottomUpAnimation);
// 动画结束后重置位置
bottomUpAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
setVisibility(View.VISIBLE);
anim_cp.setVisibility(View.VISIBLE);
avatarContainer1.setVisibility(VISIBLE);
anim_cp.startPlay(new File(currPlayPath));
}
@Override
public void onAnimationEnd(Animation animation) {
startAvatarFloatAnimation();
}
@Override
public void onAnimationRepeat(Animation animation) {}
});
avatarsParentContainer.startAnimation(bottomUpAnimation);
}
/**
* 头像上下动画
*/
private void startAvatarFloatAnimation() {
// 确保包含两个头像的父布局已初始化
if (avatarsParentContainer == null) {
return;
}
// 包含两个头像的父布局上下浮动动画
AnimationSet avatarsAnimationSet = new AnimationSet(true);
// 使用适中的移动距离,确保头像框显示完整
TranslateAnimation avatarsFloatUp = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, -0.01f);
avatarsFloatUp.setDuration(900); // 增加动画持续时间,使动画更平滑
avatarsFloatUp.setRepeatCount(Animation.INFINITE);
avatarsFloatUp.setRepeatMode(Animation.REVERSE);
avatarsAnimationSet.addAnimation(avatarsFloatUp);
avatarsParentContainer.startAnimation(avatarsAnimationSet);
}
/**
* 停止头像动画
*/
private void stopAvatarAnimation() {
if (avatarsParentContainer != null) {
avatarsParentContainer.clearAnimation();
}
}
/**
* 停止播放动画
*/
public void stopPlay() {
stopAvatarAnimation();
if (anim_cp != null) {
anim_cp.stopPlay();
anim_cp.setVisibility(View.GONE);
}
setVisibility(View.GONE);
}
/**
* 开启或关闭特效视图
* @param isShow 是否显示
*/
public void openOrCloseEffectViewWith(boolean isShow) {
this.isShow = isShow;
if (anim_cp != null) {
anim_cp.stopPlay();
anim_cp.setVisibility(View.GONE);
}
setVisibility(isShow ? View.VISIBLE : View.GONE);
}
/**
* 下载并播放动画
* @param context 上下文
* @param playImage 动画URL
* @param callback 下载回调
*/
public void downloadAndPlay(Context context, String playImage, DownloadCallback callback) {
String fileName = playImage.substring(playImage.lastIndexOf("/"));
String filePath = context.getCacheDir().getAbsolutePath() + fileName;
LogUtils.e("@@@@@filePath: " + filePath.toString());
File file = new File(filePath);
if (!file.exists()) {
LogUtils.e("无缓存");
// 使用OkHttp进行下载
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(playImage)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
LogUtils.e("MP4下载失败: " + e.toString());
// 在主线程中回调失败
post(() -> {
if (callback != null) {
callback.onError(e.getMessage());
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
try (ResponseBody responseBody = response.body()) {
if (responseBody != null) {
File downloadedFile = new File(filePath);
FileOutputStream fos = new FileOutputStream(downloadedFile);
fos.write(responseBody.bytes());
fos.close();
// 在主线程中回调成功
post(() -> {
if (callback != null) {
callback.onSuccess(downloadedFile.getAbsolutePath());
}
});
} else {
// 在主线程中回调失败
post(() -> {
if (callback != null) {
callback.onError("Response body is null");
}
});
}
} catch (Exception e) {
LogUtils.e("MP4文件保存失败: " + e.getMessage());
// 在主线程中回调失败
post(() -> {
if (callback != null) {
callback.onError(e.getMessage());
}
});
}
} else {
LogUtils.e("MP4下载响应失败");
// 在主线程中回调失败
post(() -> {
if (callback != null) {
callback.onError("Response not successful: " + response.code());
}
});
}
}
});
} else {
// 文件已存在,直接回调成功
if (callback != null) {
callback.onSuccess(file.getAbsolutePath());
}
}
}
/**
* 重新初始化视图,以便再次播放
*/
public void reinitView() {
if (anim_cp == null) {
// 如果动画视图已被销毁,重新初始化
initView();
// 重新设置动画监听器
setupAnimListener();
}
// 确保线程池可用
if (queue == null || queue.isShutdown()) {
queue = Executors.newSingleThreadExecutor();
}
// 重置状态
isLoadEffect = false;
isShow = true;
}
/**
* 完全销毁视图,释放所有资源
* 当不再需要此视图时调用
*/
public void completeDestroy() {
// 停止头像动画
stopAvatarAnimation();
// 清理监听器
clearPlaybackCompleteListeners();
// 停止并移除动画视图
if (anim_cp != null) {
anim_cp.stopPlay();
removeView(anim_cp);
anim_cp = null;
}
// 停止线程池
if (queue != null) {
queue.shutdown();
queue = null;
}
// 隐藏并移除整个视图
setVisibility(View.GONE);
if (getParent() != null) {
((ViewGroup) getParent()).removeView(this);
}
}
}

View File

@@ -6,6 +6,7 @@ import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.xscm.moduleutil.bean.GiftBean;
import com.xscm.moduleutil.utils.roomview.RoomCPView;
import java.util.List;
import java.util.concurrent.ExecutorService;
@@ -20,6 +21,8 @@ public class QXGiftPlayerManager {
private GiftAnimView fullEffectView;
private GiftAnimView chatEffectView;
private RoomCPView roomCPView;
private Context context;
private QXGiftPlayerManager(Context context) {
@@ -39,6 +42,15 @@ public class QXGiftPlayerManager {
return bgEffectView;
}
public RoomCPView getRoomCPView(){
if (roomCPView==null){
initRoomCPView();
}
return roomCPView;
}
public GiftAnimView getDefaultFullEffectView() {
if (fullEffectView == null) {
initFullEffectView();
@@ -62,10 +74,25 @@ public class QXGiftPlayerManager {
bgEffectView.setBackgroundColor(0x00000000);
bgEffectView.setClickable(false); // userInteractionEnabled = NO
// 添加全屏特效视图聊天特效视图
// 添加全屏特效视图聊天特效视图和CP视图
((ViewGroup) bgEffectView).addView(getDefaultFullEffectView());
((ViewGroup) bgEffectView).addView(getDefaultChatEffectView());
((ViewGroup) bgEffectView).addView(getRoomCPView());
}
private void initRoomCPView() {
roomCPView=new RoomCPView(context);
roomCPView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
));
// 创建专用线程池替代GCD队列
ExecutorService queue = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
Executors.defaultThreadFactory());
roomCPView.setQueue(queue);
}
public void displayFullEffectView(String gift) {
getDefaultFullEffectView().displayEffectView(gift);
}
@@ -78,6 +105,31 @@ public class QXGiftPlayerManager {
getDefaultChatEffectView().displayEffectView(gift);
}
/**
* 显示CP动画
* @param room_head1 头像1的URL
* @param room_head2 头像2的URL
* @param room_cp_name1 名称1
* @param room_cp_name2 名称2
* @param mp4Path MP4动画文件路径
*/
public void displayCPView(String room_head1, String room_head2, String room_cp_name1, String room_cp_name2, String mp4Path) {
getRoomCPView().displayEffectView(room_head1, room_head2, room_cp_name1, room_cp_name2, mp4Path);
}
/**
* 开启或关闭CP动画
* @param isShow 是否显示
*/
public void openOrCloseCPViewWith(boolean isShow) {
}
/**
* 停止CP动画
*/
public void stopCPPlay() {
}
public void openOrCloseEffectViewWith(boolean isShow) {
@@ -101,6 +153,12 @@ public class QXGiftPlayerManager {
}
chatEffectView = null;
}
if (roomCPView != null) {
// 先调用destroyEffectView方法它会自动从父视图中移除
roomCPView.destroyEffectView();
roomCPView = null;
}
if (bgEffectView != null) {
bgEffectView = null;
@@ -114,6 +172,8 @@ public class QXGiftPlayerManager {
if (chatEffectView != null) {
chatEffectView.stopPlay();
}
if (roomCPView != null) {
}
}
private void initFullEffectView() {

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:duration="2000"
android:fromYDelta="0"
android:toYDelta="-20"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:interpolator="@android:anim/accelerate_decelerate_interpolator" />
</set>

View File

@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fl"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false">
<com.tencent.qgame.animplayer.AnimView
android:id="@+id/anim_cp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.58" />
<LinearLayout
android:id="@+id/ll_head"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/guideline">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/room_cp_head1"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:src="@mipmap/ic_launcher_app"
app:riv_oval="true" />
<TextView
android:id="@+id/room_cp_name1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:enabled="true"
android:maxEms="5"
android:paddingLeft="10dp"
android:paddingTop="2dp"
android:paddingRight="10dp"
android:paddingBottom="2dp"
android:singleLine="true"
android:textColor="@color/color_999999"
android:textSize="8sp"
tools:text="" />
</LinearLayout>
<View
android:layout_width="@dimen/dp_40"
android:layout_height="0dp"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/room_cp_head2"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:src="@mipmap/ic_launcher_app"
app:riv_oval="true" />
<TextView
android:id="@+id/room_cp_name2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:enabled="true"
android:maxEms="5"
android:paddingLeft="10dp"
android:paddingTop="2dp"
android:paddingRight="10dp"
android:paddingBottom="2dp"
android:singleLine="true"
android:textColor="@color/color_999999"
android:textSize="8sp"
tools:text="" />
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -41,6 +41,7 @@ import com.tencent.imsdk.v2.V2TIMValueCallback;
import com.tencent.qcloud.tuikit.tuichat.bean.ChatInfo;
import com.xscm.modulemain.activity.WebViewActivity;
import com.xscm.modulemain.activity.main.activity.MainActivity;
import com.xscm.modulemain.activity.user.activity.HeartCpActivity;
import com.xscm.modulemain.manager.RoomManager;
import com.xscm.moduleutil.BaseEvent;
import com.xscm.moduleutil.R;
@@ -217,7 +218,7 @@ public abstract class BaseMvpActivity<P extends IPresenter, VDB extends ViewData
if (event instanceof RoomMessageEvent) {
com.xscm.moduleutil.bean.RoomGiftData.CpType text = GsonUtils.fromJson(((RoomMessageEvent) event).getText().getText().toString(),com.xscm.moduleutil.bean.RoomGiftData.CpType.class);
if (text.getCp_type() == 1) {
queren1(1,text.getText(),text.getGift_id()+"",((RoomMessageEvent) event).getText().getFromUserInfo().getUser_id()+"",((RoomMessageEvent) event).getRoomId());
queren1(1,text.getText1(),text.getGift_id()+"",((RoomMessageEvent) event).getText().getFromUserInfo().getUser_id()+"",((RoomMessageEvent) event).getRoomId());
}else if (text.getCp_type() == 2) {
queren1(2,text.getText1(),text.getGift_id()+"",((RoomMessageEvent) event).getText().getFromUserInfo().getUser_id()+"",((RoomMessageEvent) event).getRoomId());
}
@@ -334,6 +335,11 @@ public abstract class BaseMvpActivity<P extends IPresenter, VDB extends ViewData
}
}
});
}else {
int userids= Integer.parseInt(userId);
Intent intent = new Intent(ActivityUtils.getTopActivity(), HeartCpActivity.class);
intent.putExtra("userId",userids);
startActivity(intent);
}
},
v -> {

View File

@@ -345,7 +345,8 @@ class RoomActivity : BaseMvpActivity<RoomPresenter?, ActivityRoomBinding?>(),
qxRedPacketManager!!.delegate = this;
// 初始化礼物管理器
GiftDisplayManager.getInstance().setupDisplayView(mBinding!!.giftContainer)
GiftDisplayManager.getInstance().setupDisplayView(mBinding?.giftContainer)
initPublicScreenFragment()
}
@@ -1489,153 +1490,13 @@ class RoomActivity : BaseMvpActivity<RoomPresenter?, ActivityRoomBinding?>(),
roomFragment!!.handleRoomMessage(messageEvent)
}
}else if(msgType == EMMessageInfo.QXRoomMessageTypeCPText){
LogUtils.e("CPText", messageEvent.text.rights_icon)
if(messageEvent.text.rights_icon.isNotEmpty()){
mBinding?.roomCpView?.fl!!.visibility = View.VISIBLE
ImageUtils.loadHead(messageEvent.text.fromUserInfo.avatar, mBinding?.roomCpView?.roomCpHead1)
mBinding?.roomCpView?.roomCpName1?.text = messageEvent.text.fromUserInfo.nickname
mBinding?.roomCpView?.roomCpName2?.text = messageEvent.text.toUserInfo.nickname
ImageUtils.loadHead(messageEvent.text.toUserInfo.avatar, mBinding?.roomCpView?.roomCpHead2)
playVap(messageEvent.text.rights_icon, mBinding?.roomCpView?.animCp!!, true)
QXGiftPlayerManager.getInstance(this).displayCPView(messageEvent.text.fromUserInfo.avatar,messageEvent.text.toUserInfo.avatar,messageEvent.text.fromUserInfo.nickname, messageEvent.text.toUserInfo.nickname,messageEvent.text.rights_icon)
}
}
}
fun playVap(url: String, animView: AnimView, isTxk: Boolean) {
if (!FileUtils.isFileExists(this.cacheDir.absolutePath + url.substring(url.lastIndexOf("/")))) {
LogUtils.e("无缓存")
downloadAndPlay(this, url, object : GiftAnimView.DownloadCallback {
override fun onSuccess(file: File) {
post(Runnable {
animView.startPlay(file)
})
}
override fun onFailure(e: java.lang.Exception) {
LogUtils.e("MP4下载或播放失败: " + e.message)
}
})
} else {
LogUtils.e("有缓存")
if (isTxk) {
animView.setLoop(20)
}
animView.startPlay(
File(this.cacheDir.absolutePath + url.substring(url.lastIndexOf("/")))
)
}
//情侣特效播放回调
mBinding?.roomCpView?.animCp?.setAnimListener(object : IAnimListener {
override fun onFailed(errorType: Int, errorMsg: String?) {
}
override fun onVideoComplete() {
runOnUiThread {
//播放结束后隐藏
mBinding?.roomCpView?.fl.let { view ->
if (view?.visibility == View.VISIBLE) {
// 你的代码
view?.visibility = GONE
}
}
}
}
override fun onVideoDestroy() {
}
override fun onVideoRender(frameIndex: Int, config: AnimConfig?) {
}
override fun onVideoStart() {
}
})
}
fun downloadAndPlay(
context: Context,
playImage: String,
callback: GiftAnimView.DownloadCallback?
) {
val filePath = context.cacheDir.absolutePath + playImage.substring(playImage.lastIndexOf("/"))
val file = File(filePath)
if (!FileUtils.isFileExists(this.cacheDir.absolutePath + playImage.substring(playImage.lastIndexOf("/")))) {
LogUtils.e("无缓存")
// 使用OkHttp进行下载
val client = OkHttpClient()
val request = Request.Builder()
.url(playImage)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
LogUtils.e("MP4下载失败: " + e.toString())
// 在主线程中回调失败
post(Runnable {
if (callback != null) {
callback.onFailure(e)
}
})
}
@Throws(IOException::class)
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful()) {
try {
response.body().use { responseBody ->
if (responseBody != null) {
val downloadedFile = File(filePath)
val fos = FileOutputStream(downloadedFile)
fos.write(responseBody.bytes())
fos.close()
// 在主线程中回调成功
post(Runnable {
if (callback != null) {
callback.onSuccess(downloadedFile)
}
})
} else {
// 在主线程中回调失败
post(Runnable {
if (callback != null) {
callback.onFailure(IOException("Response body is null"))
}
})
}
}
} catch (e: java.lang.Exception) {
LogUtils.e("MP4文件保存失败: " + e.message)
// 在主线程中回调失败
post(Runnable {
if (callback != null) {
callback.onFailure(e)
}
})
}
} else {
LogUtils.e("MP4下载响应失败")
// 在主线程中回调失败
post(Runnable {
if (callback != null) {
callback.onFailure(IOException("Response not successful: " + response.code()))
}
})
}
}
})
} else {
// 文件已存在,直接回调成功
if (callback != null) {
callback.onSuccess(file)
}
}
}
private var endTime: Long = 0
private fun xlhDjs(endTimeStr: String?) {

View File

@@ -45,6 +45,9 @@ class HeartCpActivity : BaseMvpActivity<HeartCpPresenter, ActivityHeartCpBinding
override fun initData() {
if (userId == 0){
userId=intent.getStringExtra("userId")?.toInt()!!
}
MvpPre.getHeartCpData(userId)
mBinding.ivBack.setOnClickListener {

View File

@@ -4,13 +4,14 @@ import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.blankj.utilcode.util.ActivityUtils
import com.blankj.utilcode.util.SnackbarUtils.dismiss
import com.chad.library.adapter.base.entity.MultiItemEntity
import com.scwang.smartrefresh.layout.api.RefreshLayout
import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener
import com.xscm.modulemain.R
import com.xscm.modulemain.activity.user.activity.HeartCpActivity
import com.xscm.modulemain.activity.user.activity.RelationshipActivity
import com.xscm.modulemain.activity.user.activity.UserHomepageActivity
import com.xscm.modulemain.activity.user.conacts.UserHomepageConacts
@@ -24,7 +25,6 @@ import com.xscm.moduleutil.bean.RelationshipBean
import com.xscm.moduleutil.bean.UserInfo
import com.xscm.moduleutil.dialog.ConfirmDialog
import com.xscm.moduleutil.utils.ImageUtils
import com.xscm.moduleutil.utils.SpUtil
/**
* @Author qx
@@ -181,7 +181,9 @@ class BosomFriendFragment : BaseMvpFragment<UserHomepagePresenter?, FragmentBoso
startActivity(intent)
}
mBinding.llMiddle.setOnClickListener { //跳转到心动空间
val intent = Intent(ActivityUtils.getTopActivity(), HeartCpActivity::class.java)
intent.putExtra("userId", userId)
startActivity(intent)
}
}

View File

@@ -143,14 +143,6 @@
android:elevation="2dp"
app:layout_constraintTop_toTopOf="parent" />
<include
android:id="@+id/room_cp_view"
layout="@layout/room_cp_vip_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/main_content_container"
android:layout_width="0dp"
@@ -175,6 +167,19 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- <include-->
<!-- android:id="@+id/room_cp_view"-->
<!-- layout="@layout/room_cp_vip_view"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:elevation="10dp"-->
<!-- app:layout_constraintDimensionRatio="16:9"-->
<!-- app:layout_constraintEnd_toEndOf="@+id/vp_room_pager"-->
<!-- app:layout_constraintStart_toStartOf="@+id/vp_room_pager"-->
<!-- app:layout_constraintTop_toTopOf="@+id/vp_room_pager"-->
<!-- android:visibility="gone" />-->
<FrameLayout
android:id="@+id/ease_container"
android:layout_width="0dp"

View File

@@ -20,213 +20,14 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/im_intimate">
<TextView
android:id="@+id/tv_heartbeat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dp_54"
android:background="@mipmap/icon_heartbeat"
android:fontFamily="@font/semibold"
android:gravity="center"
android:text="心动"
android:textColor="#fff"
android:textSize="@dimen/sp_16"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<RelativeLayout
android:id="@+id/ll_cp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_10"
android:layout_marginTop="@dimen/dp_15"
android:background="@mipmap/icon_dialog_u_cp_bg"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_heartbeat">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/icon_dialog_u_cp_left_top"
android:gravity="center"
android:text="CP"
android:textColor="@color/white" />
<LinearLayout
android:id="@+id/ll_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toStartOf="@+id/ll_middle"
android:orientation="vertical">
<com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/user_nav1"
android:layout_width="@dimen/dp_50"
android:layout_height="@dimen/dp_50"
android:background="@drawable/shape_circle"
android:padding="@dimen/dp_2"
android:src="@mipmap/default_avatar"
app:riv_oval="true" />
<TextView
android:id="@+id/tv_nickname1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/user_nav1"
android:layout_alignStart="@+id/user_nav1"
android:layout_alignEnd="@+id/user_nav1"
android:layout_gravity="center"
android:ellipsize="end"
android:lines="1"
android:maxWidth="@dimen/dp_70"
android:textColor="#FF624E79"
android:textSize="@dimen/sp_10"
tools:text="用户昵称" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_middle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginHorizontal="@dimen/dp_20"
android:orientation="vertical">
<TextView
android:id="@+id/tv_cp_lv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/icon_dialog_u_cp_lv"
android:gravity="center"
android:padding="@dimen/dp_5"
android:textColor="#FFFFEAB9"
android:textSize="@dimen/sp_10"
tools:text="LV8 情缘一定" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/icon_dialog_u_cp_" />
<TextView
android:id="@+id/tv_cp_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="#FFFF0088"
android:textSize="@dimen/sp_14"
tools:text="100.35w" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@+id/ll_middle"
android:orientation="vertical">
<com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/user_nav2"
android:layout_width="@dimen/dp_50"
android:layout_height="@dimen/dp_50"
android:background="@drawable/shape_circle"
android:padding="@dimen/dp_2"
android:src="@mipmap/default_avatar"
app:riv_oval="true" />
<TextView
android:id="@+id/tv_nickname2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="end"
android:lines="1"
android:maxWidth="@dimen/dp_70"
android:text="用户昵称"
android:textColor="#FF624E79"
android:textSize="@dimen/sp_10" />
</LinearLayout>
<RelativeLayout
android:id="@+id/rl_reqit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/dp_50"
android:background="@mipmap/regit_t"
android:visibility="gone">
<TextView
android:id="@+id/tv_relation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/dp_40"
android:gravity="center"
android:textColor="@color/white"
android:textSize="@dimen/sp_12"
android:textStyle="bold"
tools:text="开始使用" />
</RelativeLayout>
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:background="@drawable/bg_r53_33333"
android:gravity="center"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:textColor="@color/white"
android:textSize="@dimen/sp_9"
android:visibility="gone"
tools:text="5天" />
</RelativeLayout>
<TextView
android:id="@+id/tv_heartbeat_ts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_24"
android:layout_marginTop="@dimen/dp_16"
android:background="@mipmap/bj_heartbeat_ts"
android:gravity="center"
android:text="暂无关系,前往房间互送特殊礼物打成关系吧"
android:textColor="#624E79"
android:textSize="@dimen/sp_12"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_heartbeat" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.scwang.smartrefresh.layout.SmartRefreshLayout
android:id="@+id/smart_refresh_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_10"
app:layout_constraintTop_toBottomOf="@+id/cc"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/im_intimate"
app:srlEnableLoadMore="true"
app:srlEnableRefresh="true">
@@ -238,6 +39,207 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView
android:id="@+id/tv_heartbeat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dp_54"
android:background="@mipmap/icon_heartbeat"
android:fontFamily="@font/semibold"
android:gravity="center"
android:text="心动"
android:textColor="#fff"
android:textSize="@dimen/sp_16"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<RelativeLayout
android:id="@+id/ll_cp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_10"
android:layout_marginTop="@dimen/dp_15"
android:background="@mipmap/icon_dialog_u_cp_bg"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_heartbeat"
tools:visibility="visible">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/icon_dialog_u_cp_left_top"
android:gravity="center"
android:text="CP"
android:textColor="@color/white" />
<LinearLayout
android:id="@+id/ll_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toStartOf="@+id/ll_middle"
android:orientation="vertical">
<com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/user_nav1"
android:layout_width="@dimen/dp_50"
android:layout_height="@dimen/dp_50"
android:background="@drawable/shape_circle"
android:padding="@dimen/dp_2"
android:src="@mipmap/default_avatar"
app:riv_oval="true" />
<TextView
android:id="@+id/tv_nickname1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/user_nav1"
android:layout_alignStart="@+id/user_nav1"
android:layout_alignEnd="@+id/user_nav1"
android:layout_gravity="center"
android:ellipsize="end"
android:lines="1"
android:maxWidth="@dimen/dp_70"
android:textColor="#FF624E79"
android:textSize="@dimen/sp_10"
tools:text="用户昵称" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_middle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginHorizontal="@dimen/dp_20"
android:orientation="vertical">
<TextView
android:id="@+id/tv_cp_lv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/icon_dialog_u_cp_lv"
android:gravity="center"
android:padding="@dimen/dp_5"
android:textColor="#FFFFEAB9"
android:textSize="@dimen/sp_10"
tools:text="LV8 情缘一定" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/icon_dialog_u_cp_" />
<TextView
android:id="@+id/tv_cp_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="#FFFF0088"
android:textSize="@dimen/sp_14"
tools:text="100.35w" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@+id/ll_middle"
android:orientation="vertical">
<com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/user_nav2"
android:layout_width="@dimen/dp_50"
android:layout_height="@dimen/dp_50"
android:background="@drawable/shape_circle"
android:padding="@dimen/dp_2"
android:src="@mipmap/default_avatar"
app:riv_oval="true" />
<TextView
android:id="@+id/tv_nickname2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="end"
android:lines="1"
android:maxWidth="@dimen/dp_70"
android:text="用户昵称"
android:textColor="#FF624E79"
android:textSize="@dimen/sp_10" />
</LinearLayout>
<RelativeLayout
android:id="@+id/rl_reqit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/dp_50"
android:background="@mipmap/regit_t"
android:visibility="gone">
<TextView
android:id="@+id/tv_relation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/dp_40"
android:gravity="center"
android:textColor="@color/white"
android:textSize="@dimen/sp_12"
android:textStyle="bold"
tools:text="开始使用" />
</RelativeLayout>
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:background="@drawable/bg_r53_33333"
android:gravity="center"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:textColor="@color/white"
android:textSize="@dimen/sp_9"
android:visibility="gone"
tools:text="5天" />
</RelativeLayout>
<TextView
android:id="@+id/tv_heartbeat_ts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_24"
android:layout_marginTop="@dimen/dp_16"
android:background="@mipmap/bj_heartbeat_ts"
android:gravity="center"
android:text="暂无关系,前往房间互送特殊礼物打成关系吧"
android:textColor="#624E79"
android:textSize="@dimen/sp_12"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_heartbeat" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- 关系列表-->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_my_relationship"

View File

@@ -601,7 +601,7 @@
android:background="@drawable/shape_dialog"
android:backgroundTint="#33FFFFFF"
android:gravity="center"
android:text="/@TA"
android:text="&#64;TA"
android:textColor="@color/white"
android:textSize="@dimen/sp_14" />

View File

@@ -1,113 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fl"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.tencent.qgame.animplayer.AnimView
android:id="@+id/anim_cp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="@dimen/dp_60"
android:gravity="center_horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginHorizontal="@dimen/dp_20"
android:orientation="vertical">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/room_cp_head1"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:src="@mipmap/ic_launcher_app"
app:riv_oval="true" />
<com.tencent.qgame.animplayer.AnimView
android:id="@+id/anim_cp_left"
android:layout_width="60dp"
android:layout_height="60dp"
android:visibility="gone"/>
</FrameLayout>
<TextView
android:id="@+id/room_cp_name1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="true"
android:maxEms="5"
android:paddingLeft="10dp"
android:paddingTop="2dp"
android:paddingRight="10dp"
android:paddingBottom="2dp"
android:singleLine="true"
android:text="欣瑶欣瑶欣瑶欣瑶"
android:textColor="@color/black"
android:textSize="8sp"
/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="3dp"
android:layout_marginHorizontal="@dimen/dp_20"
android:gravity="center"
android:orientation="vertical">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/room_cp_head2"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:src="@mipmap/ic_launcher_app"
app:riv_oval="true" />
<com.tencent.qgame.animplayer.AnimView
android:id="@+id/anim_cp_right"
android:layout_width="60dp"
android:layout_height="60dp"
android:visibility="gone"/>
</FrameLayout>
<TextView
android:id="@+id/room_cp_name2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="true"
android:maxEms="5"
android:paddingLeft="10dp"
android:paddingTop="2dp"
android:paddingRight="10dp"
android:paddingBottom="2dp"
android:singleLine="true"
android:text="欣瑶"
android:textColor="@color/black"
android:textSize="8sp"
/>
</LinearLayout>
</LinearLayout>
</FrameLayout>
</layout>