添加了动态修改背景图和首页按钮

修改了飘屏功能
This commit is contained in:
2025-08-13 17:31:52 +08:00
parent bd4e7912f1
commit 96e3c86cd4
38 changed files with 1507 additions and 165 deletions

View File

@@ -51,7 +51,7 @@ android {
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
// implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation libs.appcompat
@@ -103,8 +103,8 @@ dependencies {
// api(libs.pictureselector.picture.library)
api('io.github.lucksiege:pictureselector:v3.11.2')
///图片裁剪 (按需引入)
api ('io.github.lucksiege:ucrop:v3.11.2')
///图片裁剪 (按需引入)
api('io.github.lucksiege:ucrop:v3.11.2')
api(libs.com.github.bumptech.glide.glide)
// api(libs.glide.compiler)
@@ -187,7 +187,8 @@ dependencies {
// api project(':LocalAar')
api 'com.tencent.bugly:crashreport:latest.release' //其中latest.release指代最新Bugly SDK版本号也可以指定明确的版本号例如4.0.3
api 'com.tencent.bugly:crashreport:latest.release'
//其中latest.release指代最新Bugly SDK版本号也可以指定明确的版本号例如4.0.3
// api 'com.tencent.rqd:nativecrashreport:latest.release' //其中latest.release指代最新Bugly NDK版本号也可以指定明确的版本号例如3.9.2
// 房间引擎
api "io.trtc.uikit:rtc_room_engine:latest.release"
@@ -200,12 +201,6 @@ dependencies {
api 'io.github.petterpx:floatingx-compose:2.3.5'
api 'com.github.princekin-f:EasyFloat:2.0.4'
//MQTT
// api 'org.eclipse.paho:org.eclipse.paho.mqttv5.client:1.2.5'
// api 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.1'
// api 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
// api 'com.github.hannesa2:paho.mqtt.android:3.3.5'
// api 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5'
api 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5'
api 'io.github.mayzs:paho.mqtt.android:1.2.1'

View File

@@ -1,8 +1,11 @@
package com.qxcm.moduleutil.activity;
import static com.liulishuo.okdownload.OkDownloadProvider.context;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -20,18 +23,28 @@ import androidx.databinding.ViewDataBinding;
import com.alibaba.android.arouter.launcher.ARouter;
import com.blankj.utilcode.util.BarUtils;
import com.petterp.floatingx.FloatingX;
import com.petterp.floatingx.assist.helper.FxAppHelper;
import com.qxcm.moduleutil.R;
import com.qxcm.moduleutil.event.MqttBean;
import com.qxcm.moduleutil.utils.BackgroundManager;
import com.qxcm.moduleutil.utils.ColorManager;
import com.qxcm.moduleutil.utils.DisplayUtil;
import com.qxcm.moduleutil.utils.LanguageUtil;
import com.qxcm.moduleutil.widget.PiaoPingManager;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends AppCompatActivity
implements BackgroundManager.BackgroundUpdateListener , ColorManager.OnColorChangeListener {
public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends AppCompatActivity {
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(LanguageUtil.attachBaseContext(newBase));
@@ -60,6 +73,14 @@ public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends
initData();
initCompleted();
// 注册背景更新监听器
BackgroundManager.getInstance().addListener(this);
// 尝试加载网络背景
loadNetworkBackground();
// 注册颜色变化监听器
ColorManager.getInstance().addColorChangeListener(this);
// 应用当前颜色
applyCurrentColors();
// 动态判断是否包含 @Subscribe 注解的方法
@@ -94,7 +115,78 @@ public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends
}
}
}
/**
* 应用当前颜色设置
*/
protected void applyCurrentColors() {
onColorChanged(ColorManager.getInstance());
}
/**
* 颜色变化回调
*/
@Override
public void onColorChanged(ColorManager colorManager) {
// 子类可以重写此方法来处理颜色变化
// 默认实现为空,由子类决定如何应用颜色
}
/**
* 更新主题颜色(从服务器获取数据后调用)
* @param serverColorMap 服务器返回的颜色配置
*/
protected void updateThemeColors(Map<String, String> serverColorMap) {
ColorManager.getInstance().updateColors(serverColorMap);
}
/**
* 更新单个颜色
* @param colorKey 颜色键名
* @param colorHex 颜色值HEX格式
*/
protected void updateThemeColor(String colorKey, String colorHex) {
ColorManager.getInstance().updateColor(colorKey, colorHex);
}
protected void loadNetworkBackground() {
// 只有当已经有背景URL时才加载
String backgroundUrl = BackgroundManager.getInstance().getBackgroundUrl();
if (backgroundUrl != null && !backgroundUrl.isEmpty()) {
// 检查是否有已加载的drawable
Drawable cachedDrawable = BackgroundManager.getInstance().getBackgroundDrawable();
if (cachedDrawable != null) {
getWindow().getDecorView().setBackground(cachedDrawable);
} else {
// 加载网络背景
BackgroundManager.getInstance().loadBackgroundDrawable(this, new BackgroundManager.BackgroundLoadCallback() {
@Override
public void onLoadSuccess(Drawable drawable) {
getWindow().getDecorView().setBackground(drawable);
}
@Override
public void onLoadFailed() {
// 加载失败时使用默认背景
getWindow().getDecorView().setBackgroundResource(R.mipmap.activity_bj);
}
});
}
}
}
@Override
public void onBackgroundUpdated(Drawable drawable) {
// 当背景更新时更新当前Activity的背景
if (drawable != null) {
getWindow().getDecorView().setBackground(drawable);
}
}
// 提供一个方法供子类调用用于设置背景URL
protected void setNetworkBackgroundUrl(String url) {
BackgroundManager.getInstance().setBackgroundUrl(url);
}
@Override
public Resources getResources() {//禁止app字体大小跟随系统字体大小调节
Resources resources = super.getResources();
if (resources != null && resources.getConfiguration().fontScale != 1.0f) {
@@ -130,6 +222,10 @@ public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends
@Override
protected void onDestroy() {
// 移除背景更新监听器
BackgroundManager.getInstance().removeListener(this);
// 移除颜色变化监听器
ColorManager.getInstance().removeColorChangeListener(this);
if (mBinding != null) {
mBinding.unbind();
}
@@ -201,4 +297,11 @@ public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends
}
return false;
}
// @Subscribe(threadMode = ThreadMode.MAIN)
// public void onMessageReceived(MqttBean mqttBean) {
//// PiaoPingManager.getInstance(this).showPiaoPingMessage(mqttBean);
// FxAppHelper fxAppHelper = FxAppHelper.builder().setContext(this).setLayout(R.layout.item_piaoping).build();
// FloatingX.install(fxAppHelper).show();
// }
}

View File

@@ -113,8 +113,9 @@ public class CommonAppContext extends MultiDexApplication {
super.onCreate();
sInstance = this;
sMainThreadHandler = new Handler();
EnvironmentPrefs prefs = new EnvironmentPrefs(this);
currentEnvironment = prefs.getSelectedEnvironment();
initialization();
}
public void initialization(){
@@ -128,8 +129,7 @@ public class CommonAppContext extends MultiDexApplication {
UtilConfig.checkInEmulator();
}
}
EnvironmentPrefs prefs = new EnvironmentPrefs(this);
currentEnvironment = prefs.getSelectedEnvironment();
piaoPingManager = PiaoPingManager.getInstance(this);
piaoPingManager.subscribe();
AgoraManager.getInstance(this).init(currentEnvironment.getSwSdkAppId());

View File

@@ -0,0 +1,25 @@
package com.qxcm.moduleutil.bean;
import lombok.Data;
/**
* @author qx
* @data 2025/8/12
* @description: 主题接口,修改主题返回的值
*/
@Data
public class ThemeBean {
private String theme_color;//主题颜色
private String file_url;//
private String auxiliary_color;//
private String btn_text_color;//按钮文字颜色
private String app_bg;//app背景图
private String home_sel;//首页选中
private String home_nor;//首页未选中
private String find_sel;//广场选中
private String find_nor;//广场未选中
private String msg_sel;//消息选中
private String msg_nor;//消息未选中
private String mine_sel;//我的选中
private String mine_nor;//我的未选中
}

View File

@@ -47,6 +47,7 @@ import com.qxcm.moduleutil.bean.RoomTime;
import com.qxcm.moduleutil.bean.RoomTypeModel;
import com.qxcm.moduleutil.bean.RoonGiftModel;
import com.qxcm.moduleutil.bean.SongMusicBean;
import com.qxcm.moduleutil.bean.ThemeBean;
import com.qxcm.moduleutil.bean.TopRoom;
import com.qxcm.moduleutil.bean.UserBean;
import com.qxcm.moduleutil.bean.UserInfo;
@@ -236,6 +237,9 @@ public interface ApiServer {
@POST(Constants.URL_LOGIN)
Call<BaseModel<List<UserBean>>> oauthLogin(@Field("login_token") String login_token);
@GET(Constants.GET_THEME_DATA)
Call<BaseModel<ThemeBean>> getThemeData();
@FormUrlEncoded
@POST(Constants.URL_AUTH_CODE)
Observable<BaseModel<List<UserBean>>> authCode(@Field("auth_code") String login_token);

View File

@@ -64,6 +64,7 @@ import com.qxcm.moduleutil.bean.RoomTime;
import com.qxcm.moduleutil.bean.RoomTypeModel;
import com.qxcm.moduleutil.bean.RoonGiftModel;
import com.qxcm.moduleutil.bean.SongMusicBean;
import com.qxcm.moduleutil.bean.ThemeBean;
import com.qxcm.moduleutil.bean.TopRoom;
import com.qxcm.moduleutil.bean.UserBean;
import com.qxcm.moduleutil.bean.UserFollowBean;
@@ -717,6 +718,28 @@ public class RetrofitClient {
});
}
public void getThemeData(BaseObserver<ThemeBean> observer){
sApiServer.getThemeData().enqueue(new Callback<BaseModel<ThemeBean>>() {
@Override
public void onResponse(Call<BaseModel<ThemeBean>> call, Response<BaseModel<ThemeBean>> response) {
if (response.code() == 200){
BaseModel<ThemeBean> baseModel = response.body();
if (baseModel.getData()!=null){
observer.onNext(baseModel.getData());
}else {
observer.onNext(null);
}
}
}
@Override
public void onFailure(Call<BaseModel<ThemeBean>> call, Throwable t) {
t.printStackTrace();
}
});
}
public void authCode(String netease_token, int type, BaseObserver<List<UserBean>> observer) {
if (type == 1) {
sApiServer.authCode1(netease_token).compose(new DefaultTransformer<>()).subscribe(observer);

View File

@@ -44,9 +44,8 @@ public class MyMqttService extends Service implements MyEmqttConnectListener,MyE
private final static String TAG = "lxj";
private static int qos = 2;
private static String HOST = CommonAppContext.getInstance().getCurrentEnvironment().getMqttUrl();
// private static String USERNAME = BuildConfig.EMQTT_USER;//用户名
// private static String PASSWORD = BuildConfig.EMQTT_PASSWORD;//密码
private static String HOST ="tcp://81.70.45.221";//正式
// private static String HOST ="tcp://47.120.21.132";//测试
private static MqttAndroidClient mqttAndroidClient;
private MqttConnectOptions mMqttConnectOptions;
private static boolean b = true;

View File

@@ -0,0 +1,112 @@
// 在 moduleUtil 中创建 BackgroundManager.java
package com.qxcm.moduleutil.utils;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import java.util.ArrayList;
import java.util.List;
/**
*@author qx
*@data 2025/8/12
*@description: 背景图片的单例类
*/
public class BackgroundManager {
private static BackgroundManager instance;
private String backgroundUrl;
private Drawable backgroundDrawable;
private List<BackgroundUpdateListener> listeners = new ArrayList<>();
public static BackgroundManager getInstance() {
if (instance == null) {
synchronized (BackgroundManager.class) {
if (instance == null) {
instance = new BackgroundManager();
}
}
}
return instance;
}
public void setBackgroundUrl(String url) {
this.backgroundUrl = url;
loadBackground();
}
public String getBackgroundUrl() {
return backgroundUrl;
}
public Drawable getBackgroundDrawable() {
return backgroundDrawable;
}
private void loadBackground() {
if (backgroundUrl == null || backgroundUrl.isEmpty()) {
return;
}
// 这里使用一个临时的 ImageView 来加载图片
// 实际项目中可能需要使用 Application Context
// 为简化,这里直接加载到 drawable
}
public void loadBackgroundDrawable(android.content.Context context, BackgroundLoadCallback callback) {
if (backgroundUrl == null || backgroundUrl.isEmpty()) {
callback.onLoadFailed();
return;
}
Glide.with(context)
.asDrawable()
.load(backgroundUrl)
.into(new CustomTarget<Drawable>() {
@Override
public void onResourceReady(Drawable resource, Transition<? super Drawable> transition) {
backgroundDrawable = resource;
callback.onLoadSuccess(resource);
notifyBackgroundUpdated(resource);
}
@Override
public void onLoadCleared(Drawable placeholder) {
callback.onLoadFailed();
}
@Override
public void onLoadFailed(Drawable errorDrawable) {
super.onLoadFailed(errorDrawable);
callback.onLoadFailed();
}
});
}
public void addListener(BackgroundUpdateListener listener) {
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
public void removeListener(BackgroundUpdateListener listener) {
listeners.remove(listener);
}
private void notifyBackgroundUpdated(Drawable drawable) {
for (BackgroundUpdateListener listener : listeners) {
listener.onBackgroundUpdated(drawable);
}
}
public interface BackgroundLoadCallback {
void onLoadSuccess(Drawable drawable);
void onLoadFailed();
}
public interface BackgroundUpdateListener {
void onBackgroundUpdated(Drawable drawable);
}
}

View File

@@ -0,0 +1,279 @@
package com.qxcm.moduleutil.utils;
import android.graphics.Color;
import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author qx
* @data 2025/8/13
* @description: 颜色的管理器,从服务器获取的颜色数据,进行更改,
* 这里是两个颜色,一个主题色,一个是按钮文字颜色
*/
public class ColorManager {
// 单例实例
private static volatile ColorManager instance;
// 存储颜色值的Map
private Map<String, Integer> colorMap;
// 默认颜色值
private Map<String, Integer> defaultColors;
// 颜色变化监听器列表
private List<OnColorChangeListener> colorChangeListeners;
// 私有构造函数
private ColorManager() {
colorMap = new HashMap<>();
defaultColors = new HashMap<>();
colorChangeListeners = new ArrayList<>();
// 初始化默认颜色值
initDefaultColors();
}
/**
* 获取单例实例
*/
public static ColorManager getInstance() {
if (instance == null) {
synchronized (ColorManager.class) {
if (instance == null) {
instance = new ColorManager();
}
}
}
return instance;
}
/**
* 初始化默认颜色值
*/
private void initDefaultColors() {
// 主题色
defaultColors.put("theme_color", Color.parseColor("#4CAF50")); // 绿色(按您的需求)
defaultColors.put("btn_text_color", Color.parseColor("#FFFFFF")); // 白色
}
/**
* 根据服务器返回的数据更新颜色
*
* @param colorKey 颜色键名
* @param colorHex 颜色HEX值 (#FFFFFF格式)
*/
public void updateColor(String colorKey, @Nullable String colorHex) {
boolean changed = false;
if (colorHex != null && !colorHex.isEmpty()) {
try {
int color = Color.parseColor(colorHex);
Integer oldColor = colorMap.get(colorKey);
if (oldColor == null || oldColor != color) {
colorMap.put(colorKey, color);
changed = true;
}
} catch (Exception e) {
// 解析失败时移除该颜色,使用默认值
if (colorMap.containsKey(colorKey)) {
colorMap.remove(colorKey);
changed = true;
}
e.printStackTrace();
}
} else {
// 如果返回空值,则移除该颜色,使用默认值
if (colorMap.containsKey(colorKey)) {
colorMap.remove(colorKey);
changed = true;
}
}
// 如果颜色发生了变化,通知监听器
if (changed) {
notifyColorChanged();
}
}
/**
* 批量更新颜色
*
* @param colorMap 服务器返回的颜色Map
*/
public void updateColors(Map<String, String> colorMap) {
boolean changed = false;
if (colorMap != null) {
for (Map.Entry<String, String> entry : colorMap.entrySet()) {
String colorKey = entry.getKey();
String colorHex = entry.getValue();
if (colorHex != null && !colorHex.isEmpty()) {
try {
int color = Color.parseColor(colorHex);
Integer oldColor = this.colorMap.get(colorKey);
if (oldColor == null || oldColor != color) {
this.colorMap.put(colorKey, color);
changed = true;
}
} catch (Exception e) {
// 解析失败时移除该颜色
if (this.colorMap.containsKey(colorKey)) {
this.colorMap.remove(colorKey);
changed = true;
}
e.printStackTrace();
}
} else {
// 如果返回空值,则移除该颜色
if (this.colorMap.containsKey(colorKey)) {
this.colorMap.remove(colorKey);
changed = true;
}
}
}
}
// 如果有任何颜色发生了变化,通知监听器
if (changed) {
notifyColorChanged();
}
}
/**
* 获取颜色值
*
* @param colorKey 颜色键名
* @return 颜色值,如果未设置则返回默认值
*/
@ColorInt
public int getColor(String colorKey) {
// 先从服务器设置的颜色中查找
if (colorMap.containsKey(colorKey)) {
return colorMap.get(colorKey);
}
// 如果没有设置,则返回默认颜色
if (defaultColors.containsKey(colorKey)) {
return defaultColors.get(colorKey);
}
// 如果默认颜色也没有定义,则返回黑色
return Color.BLACK;
}
/**
* 获取颜色值,带默认返回值
*
* @param colorKey 颜色键名
* @param defaultColor 默认颜色
* @return 颜色值
*/
@ColorInt
public int getColor(String colorKey, @ColorInt int defaultColor) {
if (colorMap.containsKey(colorKey)) {
return colorMap.get(colorKey);
}
return defaultColor;
}
/**
* 检查是否设置了指定颜色
*
* @param colorKey 颜色键名
* @return 是否设置了该颜色
*/
public boolean hasColor(String colorKey) {
return colorMap.containsKey(colorKey);
}
/**
* 获取默认颜色
*
* @param colorKey 颜色键名
* @return 默认颜色值
*/
@ColorInt
public int getDefaultColor(String colorKey) {
if (defaultColors.containsKey(colorKey)) {
return defaultColors.get(colorKey);
}
return Color.BLACK;
}
/**
* 重置所有颜色为默认值
*/
public void resetToDefault() {
if (!colorMap.isEmpty()) {
colorMap.clear();
notifyColorChanged();
}
}
/**
* 移除指定颜色设置,恢复为默认值
*
* @param colorKey 颜色键名
*/
public void removeColor(String colorKey) {
if (colorMap.containsKey(colorKey)) {
colorMap.remove(colorKey);
notifyColorChanged();
}
}
/**
* 获取所有当前设置的颜色(不包括默认颜色)
*
* @return 当前设置的颜色Map
*/
public Map<String, Integer> getCurrentColors() {
return new HashMap<>(colorMap);
}
/**
* 获取所有默认颜色
*
* @return 默认颜色Map
*/
public Map<String, Integer> getDefaultColors() {
return new HashMap<>(defaultColors);
}
/**
* 添加颜色变化监听器
*/
public void addColorChangeListener(OnColorChangeListener listener) {
if (!colorChangeListeners.contains(listener)) {
colorChangeListeners.add(listener);
}
}
/**
* 移除颜色变化监听器
*/
public void removeColorChangeListener(OnColorChangeListener listener) {
colorChangeListeners.remove(listener);
}
/**
* 通知颜色变化
*/
private void notifyColorChanged() {
for (OnColorChangeListener listener : colorChangeListeners) {
listener.onColorChanged(this);
}
}
/**
* 颜色变化监听器接口
*/
public interface OnColorChangeListener {
void onColorChanged(ColorManager colorManager);
}
}

View File

@@ -156,9 +156,17 @@ public class AvatarFrameView extends FrameLayout implements IAnimListener {
return "";
}
private void playNextFromQueue() {
// 检查特效是否开启
if (SpUtil.getOpenEffect() != 1) {
clearQueue();
return;
}
PlayItem item = playQueue.poll();
if (item != null) {
isPlaying = false;
isPlaying = true;
Logger.d("AvatarFrameView", "Playing item, remaining queue size: " + playQueue.size());
RenderType type = null;
String ext = getFileExtension(item.url);
if ("svga".equalsIgnoreCase(ext)) {
@@ -190,43 +198,63 @@ public class AvatarFrameView extends FrameLayout implements IAnimListener {
}
} else {
isPlaying = false;
Logger.d("AvatarFrameView", "Queue is empty, stop playing");
}
}
public void setSource(String url, int type2) {
// 检查特效是否开启
if (SpUtil.getOpenEffect() != 1) {
// 特效关闭时清空队列并停止播放
clearQueue();
return;
}
// 添加到播放队列
// playQueue.offer(new PlayItem(url, type2));
playQueue.add(new PlayItem(url, type2));
Logger.d("AvatarFrameView", "Added to queue, queue size: " + playQueue.size() + ", url: " + url);
// 如果当前没有在播放,则开始播放
if (!isPlaying) {
playNextFromQueue();
}
}
public void setSource(String url, int type2) {
if (SpUtil.getOpenEffect()==1) {
playQueue.offer(new PlayItem(url, type2));
if (!isPlaying) {
playNextFromQueue();
}
}else {
playQueue.clear();
isPlaying = false;
}
// RenderType type = null;
// if ("svga".equalsIgnoreCase(getFileExtension(url))){
// type = RenderType.SVGA;
// }else if ("mp4".equalsIgnoreCase(getFileExtension(url))){
// type = RenderType.MP4;
// public void setSource(String url, int type2) {
// if (SpUtil.getOpenEffect()==1) {
// playQueue.offer(new PlayItem(url, type2));
// if (!isPlaying) {
// playNextFromQueue();
// }
// }else {
// playQueue.clear();
// isPlaying = false;
// }
//
// clearPrevious();
// renderType = type;
// mType = type2;
// switch (type) {
// case SVGA:
// mBinding.playView.stopPlay();
// mBinding.playView.setVisibility(View.GONE);
// loadSVGA(url);
// break;
// case MP4:
//// loadMP4(url);
// mBinding.playView.setVisibility(View.VISIBLE);
// downloadAndPlayMp4(url);
// break;
// }
}
//// RenderType type = null;
//// if ("svga".equalsIgnoreCase(getFileExtension(url))){
//// type = RenderType.SVGA;
//// }else if ("mp4".equalsIgnoreCase(getFileExtension(url))){
//// type = RenderType.MP4;
//// }
////
//// clearPrevious();
//// renderType = type;
//// mType = type2;
//// switch (type) {
//// case SVGA:
//// mBinding.playView.stopPlay();
//// mBinding.playView.setVisibility(View.GONE);
//// loadSVGA(url);
//// break;
//// case MP4:
////// loadMP4(url);
//// mBinding.playView.setVisibility(View.VISIBLE);
//// downloadAndPlayMp4(url);
//// break;
//// }
// }
private void downloadAndPlayMp4(String url) {
String filePath = PathUtils.getInternalAppCachePath() + Md5Utils.getStringMD5(url) + ".mp4";

View File

@@ -295,10 +295,16 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
if (pitBean.getUser_id().equals(userId + "")) {
iv_on_line.setVisibility(VISIBLE);
}
}else if (pitBean.getUser_id()==null || pitBean.getUser_id().equals("0") || pitBean.getUser_id().equals("")){
iv_on_line.setVisibility(GONE);
}
}
});
if (pitBean.getUser_id()==null || pitBean.getUser_id().equals("0") || pitBean.getUser_id().equals("") ){
iv_on_line.setVisibility(GONE);
}
}

View File

@@ -369,6 +369,7 @@ public class Constants {
public static final String postRoomSwToken = "/api/Room/update_user_sw_token";//获取用户声网token
public static final String dailyTasksComplete = "/api/Dailytasks/dailyTasksComplete";//领取每日任务奖励
public static final String POST_CANCEL_USER_DECORATE = "/api/Decorate/cancel_user_decorate";//取消装扮
public static final String GET_THEME_DATA = "/api/Theme/get_theme_data";//主题接口

View File

@@ -2,15 +2,19 @@ package com.qxcm.moduleutil.widget;
import static com.liulishuo.okdownload.OkDownloadProvider.context;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Build;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.petterp.floatingx.FloatingX;
import com.petterp.floatingx.assist.FxGravity;
import com.petterp.floatingx.assist.helper.FxAppHelper;
import com.qxcm.moduleutil.R;
import com.qxcm.moduleutil.event.MqttBean;
import com.qxcm.moduleutil.utils.ImageUtils;
@@ -18,6 +22,7 @@ import com.qxcm.moduleutil.utils.ImageUtils;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
/**
* @Author
* @Time 2025/7/18 21:52
@@ -46,42 +51,44 @@ public class PiaoPingManager {
}
public void showPiaoPingMessage(MqttBean mqttBean) {
if (isPiaoPingShown || piaoPingView == null || windowManager == null) return;
// 创建 FloatingX 配置
// 设置布局参数
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT,
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
layoutParams.gravity = Gravity.TOP;
layoutParams.y = 100; // 设置垂直位置
// 设置消息内容
View piaoPingView = LayoutInflater.from(context.getApplicationContext()).inflate(R.layout.item_piaoping, null);
TextView textView = piaoPingView.findViewById(R.id.tv_name);
TextView textView2 = piaoPingView.findViewById(R.id.tv_to_name);
textView2.setText("送给"+mqttBean.getList().getToUserName());
// 获取悬浮窗视图并设置内容
// 替换第72行及后续对 layoutView 的直接访问
View floatingView = LayoutInflater.from(context).inflate(R.layout.item_piaoping, new FrameLayout(context), false);
TextView textView = floatingView.findViewById(R.id.tv_name);
TextView textView2 = floatingView.findViewById(R.id.tv_to_name);
textView2.setText("送给" + mqttBean.getList().getToUserName());
textView.setText(mqttBean.getList().getFromUserName());
ImageUtils.loadHeadCC(mqttBean.getList().getGift_picture(), piaoPingView.findViewById(R.id.iv_piaoping));
TextView tv_time = piaoPingView.findViewById(R.id.tv_num);
tv_time.setText("x"+mqttBean.getList().getNumber());
ImageUtils.loadHeadCC(mqttBean.getList().getGift_picture(), floatingView.findViewById(R.id.iv_piaoping));
TextView tv_time = floatingView.findViewById(R.id.tv_num);
tv_time.setText("x" + mqttBean.getList().getNumber());
// 添加到窗口管理器
windowManager.addView(piaoPingView, layoutParams);
isPiaoPingShown = true;
// 3秒后执行左侧滑动关闭动画
floatingView.postDelayed(() -> {
// 实现左侧滑出动画
ObjectAnimator animator = ObjectAnimator.ofFloat(floatingView, "translationX", 0f, -floatingView.getWidth());
animator.setDuration(300); // 300ms 动画时间
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// 动画结束后移除悬浮窗
FloatingX.uninstallAll();
}
});
animator.start();
}, 3000);
// 设置定时任务,一段时间后移除飘屏消息
piaoPingView.postDelayed(() -> {
if (piaoPingView != null) {
windowManager.removeView(piaoPingView);
isPiaoPingShown = false;
}
}, 3000); // 3秒后移除
assert floatingView != null;
FxAppHelper fxAppHelper = FxAppHelper.builder()
.setContext(context)
.setLayoutView(floatingView)
.setGravity(FxGravity.LEFT_OR_TOP)
.setY(100)
.build();
FloatingX.install(fxAppHelper).show();
}
public void subscribe() {
@@ -95,6 +102,9 @@ public class PiaoPingManager {
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageReceived(MqttBean mqttBean) {
showPiaoPingMessage(mqttBean);
// FxAppHelper fxAppHelper = FxAppHelper.builder().setContext( context).setLayout(R.layout.item_piaoping).build();
// FloatingX.install(fxAppHelper).show();
}
}

View File

@@ -0,0 +1,254 @@
package com.qxcm.moduleutil.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.qxcm.moduleutil.R;
import com.qxcm.moduleutil.bean.UserInfo;
import com.qxcm.moduleutil.bean.room.RoomPitBean;
import com.qxcm.moduleutil.utils.ImageUtils;
import com.qxcm.moduleutil.utils.SpUtil;
/**
*@author qx
*@data 2025/8/13
*@description: K歌模式下的视图
*/
public class RoomKtvWheatView extends BaseWheatView {
public ImageView mIvTagBoss;
public TextView mTvTime;
public TextView tv_time_pk;
private boolean showBoss;//显示老板标识
public RoomKtvWheatView(Context context) {
this(context, null, 0);
}
public RoomKtvWheatView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoomKtvWheatView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void initPit(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoomDefaultWheatView);
pitNumber = typedArray.getString(R.styleable.RoomDefaultWheatView_room_wheat_number);
typedArray.recycle();
mIvTagBoss = findViewById(R.id.iv_tag_boos);
mTvTime = findViewById(R.id.tv_time);
tv_time_pk = findViewById(R.id.tv_time_pk);
}
@Override
protected int getLayoutId() {
return R.layout.room_view_ktv_wheat;
}
@Override
protected void setPitData(RoomPitBean bean) {
sex = bean.getSex();
if (isOn()) {
//开启声浪
mIvRipple.stopAnimation();
mIvRipple.setVisibility(VISIBLE);
mTvName.setText(bean.getNickname());
ImageUtils.loadHeadCC(bean.getAvatar(), mRiv);
if (TextUtils.isEmpty(pitBean.getDress())) {
mIvFrame.setVisibility(INVISIBLE);
} else {
mIvFrame.setVisibility(VISIBLE);
mIvFrame.setSource(pitBean.getDress(), 1);
// ImageUtils.loadDecorationAvatar(pitBean.getDress_picture(), mIvFrame);
}
if (showBoss && WHEAT_BOSS.equals(pitNumber)) {
mIvTagBoss.setVisibility(GONE);
}
} else {
mTvName.setText(
"-1".equals(pitNumber) ? "" :
"9".equals(pitNumber) ? "主持位" :
"10".equals(pitNumber) ? "嘉宾位" :
pitNumber + "号麦位"
);
//麦位上锁
if (showBoss && WHEAT_BOSS.equals(pitNumber)) {
mIvTagBoss.setVisibility(VISIBLE);
ImageUtils.loadRes(isLocked() ? R.mipmap.room_ic_wheat_default_suo : R.mipmap.room_ic_wheat_default, mRiv);
} else {
// mIvTagBoss.setVisibility(GONE);
// @DrawableRes int origin = getOriginImage();
// ImageUtils.loadRes(isLocked() ? R.mipmap.room_ic_wheat_default_suo :
// (origin == 0 ? R.mipmap.room_ic_wheat_default : origin), mRiv);
mRiv.setImageResource(bean.getIs_lock() == 1 ? R.mipmap.room_ic_wheat_default_suo : R.mipmap.room_ic_wheat_default);
// ImageUtils.loadRes(isLocked() ? R.mipmap.room_ic_wheat_default_suo : R.mipmap.room_ic_wheat_default, mRiv);
}
if (isMute()) {
ImageUtils.loadRes(R.mipmap.room_microphone_off, mIvSex);
}
mIvFrame.setVisibility(INVISIBLE);
mIvFace.remove();
//停止声浪
mIvRipple.stopAnimation();
mIvRipple.setVisibility(GONE);
}
if (showSexIcon) {
checkSex();
}
if (pitBean.getNickname() == null || pitBean.getNickname().isEmpty()) {
mCharmView.setVisibility(GONE);
} else {
mCharmView.setVisibility(VISIBLE);
}
if (pitBean.is_pk() ){
if (pitBean.getUser_id()!=null && !pitBean.getUser_id().equals("0") && !pitBean.getUser_id().isEmpty()) {
tv_time_pk.setVisibility(VISIBLE);
setSex(pitBean.getCharm(),false);
mCharmView.setVisibility(GONE);
}else {
tv_time_pk.setVisibility(GONE);
}
// ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mCharmView.getLayoutParams();
// params.width = 35;
// mCharmView.setLayoutParams(params);
}else {
tv_time_pk.setVisibility(GONE);
mCharmView.setVisibility(VISIBLE);
// ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mCharmView.getLayoutParams();
// params.width = 52;
// mCharmView.setLayoutParams(params);
}
// setCardiac(pitBean.getPit_number(), 0.0f);
}
public void setSex( String value, boolean format) {
if (format) {
tv_time_pk.setText(value);
} else {
try {
long xd = Long.parseLong(value);
if (xd > 9999 || xd < -9999) {
tv_time_pk.setText(String.format("%.2fw", xd / 10000.0f));
// mBinding.tvValue.setText(String.valueOf(xd));
} else {
tv_time_pk.setText(value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private boolean showSexIcon = false;
private String sex;
public boolean isMale() {
return "1".equals(sex);
}
public boolean isFemale() {
return "2".equals(sex);
}
public void setShowSexIcon(boolean show) {
showSexIcon = show;
}
public void checkSex() {
if (isOn()) {
mIvSex.setVisibility(VISIBLE);
if (!TextUtils.isEmpty(sex)) {
if (UserInfo.MALE.equals(sex)) {
mIvSex.setBackgroundResource(R.drawable.room_xq_wheat_male_mask);
if (mTvNo != null) mTvNo.setBackgroundResource(R.mipmap.ic_room_xq_wno_male);
} else {
mIvSex.setBackgroundResource(R.drawable.room_xq_wheat_female_mask);
if (mTvNo != null) mTvNo.setBackgroundResource(R.mipmap.ic_room_xq_wno_female);
}
} else {
mIvSex.setVisibility(GONE);
if (mTvNo != null) mTvNo.setBackgroundResource(getOriginNoImage());
}
} else {
mIvSex.setVisibility(GONE);
if (mTvNo != null) mTvNo.setBackgroundResource(getOriginNoImage());
}
}
/**
* 是否显示老板标识
*/
public void setIsBossShow(String is_boss_pit) {
showBoss = "1".equals(is_boss_pit);
}
/**
* 开启计时
*/
public void setTime(int time) {
if (time == 0) {
mTvTime.setText("");
mTvTime.setVisibility(INVISIBLE);
} else {
mTvTime.setText(String.format("%s'%s", time / 60, time % 60));
mTvTime.setVisibility(VISIBLE);
}
}
public void hideMaoziIcon() {
View maozi = findViewById(R.id.iv_maozi);
if (maozi != null) maozi.setVisibility(GONE);
}
@Override
public void onRemoteSoundLevelUpdate(String userId, int soundLevel) {
}
@Override
public void onLocalSoundLevelUpdate(int volume) {
if (volume==0){
mIvRipple.stopAnimation();
} else {
if (pitBean.getUser_id().equals(SpUtil.getUserId()) && closePhone) {
mIvRipple.stopAnimation();
}else {
mIvRipple.post(() -> {
if (!mIvRipple.isAnimating()) {
mIvRipple.startAnimation();
}
mIvRipple.setVisibility(VISIBLE);
});
}
}
}
@Override
public void userJoined(int userId, int elapsd) {
if (pitBean != null && pitBean.getUser_id() != null && !pitBean.getUser_id().equals("0")) {
if (pitBean.getUser_id().equals(userId + "")) {
iv_on_line.setVisibility(GONE);
}
}
}
@Override
public void userOffline(int userId, int reason) {
if (pitBean != null && pitBean.getUser_id() != null && !pitBean.getUser_id().equals("0")) {
if (pitBean.getUser_id().equals(userId + "")) {
iv_on_line.setVisibility(VISIBLE);
}
}
}
}

View File

@@ -90,12 +90,7 @@ public class RoomMakeWheatView extends BaseWheatView {
mIvTagBoss.setVisibility(VISIBLE);
ImageUtils.loadRes(isLocked() ? R.mipmap.room_ic_wheat_default_suo : R.mipmap.room_ic_wheat_default, mRiv);
} else {
// mIvTagBoss.setVisibility(GONE);
// @DrawableRes int origin = getOriginImage();
// ImageUtils.loadRes(isLocked() ? R.mipmap.room_ic_wheat_default_suo :
// (origin == 0 ? R.mipmap.room_ic_wheat_default : origin), mRiv);
mRiv.setImageResource(bean.getIs_lock()==1 ? R.mipmap.room_ic_wheat_default_suo : R.mipmap.room_ic_wheat_default);
// ImageUtils.loadRes(isLocked() ? R.mipmap.room_ic_wheat_default_suo : R.mipmap.room_ic_wheat_default, mRiv);
}
if (isMute()){
ImageUtils.loadRes(R.mipmap.room_microphone_off, mIvSex);

View File

@@ -0,0 +1,273 @@
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false">
<!--说话动态图 (麦圈) - 与头像大小相同-->
<com.opensource.svgaplayer.SVGAImageView
android:id="@+id/iv_ripple"
android:layout_width="0dp"
android:layout_height="0dp"
app:autoPlay="false"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHeight_default="percent"
app:layout_constraintHeight_percent="0.5"
app:loopCount="0"
app:source="ripple3695.svga" />
<!--头像 - 占整体高度的一半-->
<com.qxcm.moduleutil.widget.GifAvatarOvalView
android:id="@+id/riv"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="@dimen/dp_12"
android:layout_marginEnd="@dimen/dp_12"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:src="@mipmap/room_ic_wheat_default"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHeight_default="percent"
app:layout_constraintHeight_percent="0.5" />
<!--头像框 - 比头像大2dp-->
<com.qxcm.moduleutil.widget.AvatarFrameView
android:id="@+id/iv_frame"
android:layout_width="0dp"
android:layout_height="0dp"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintTop_toTopOf="@id/riv"
app:layout_constraintStart_toStartOf="@id/riv"
app:layout_constraintEnd_toEndOf="@id/riv"
app:layout_constraintBottom_toBottomOf="@id/riv"
android:layout_marginTop="-1dp"
android:layout_marginStart="-1dp"
android:layout_marginEnd="-1dp"
android:layout_marginBottom="-1dp" />
<!--离线状态 - 和头像框一样大,在标签下面-->
<ImageView
android:id="@+id/iv_online"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone"
android:src="@mipmap/room_ic_owner_offline"
android:scaleType="centerCrop"
app:layout_constraintTop_toTopOf="@id/iv_frame"
app:layout_constraintStart_toStartOf="@id/iv_frame"
app:layout_constraintEnd_toEndOf="@id/iv_frame"
app:layout_constraintBottom_toBottomOf="@id/iv_frame"
app:loopCount="0"
tools:visibility="visible" />
<!--标签位置 - 在头像底部覆盖5dp头像-->
<ImageView
android:id="@+id/iv_tag_type"
android:layout_width="@dimen/dp_30"
android:layout_height="@dimen/dp_20"
android:src="@mipmap/zc"
app:layout_constraintTop_toBottomOf="@id/riv"
app:layout_constraintStart_toStartOf="@id/riv"
app:layout_constraintEnd_toEndOf="@id/riv"
android:layout_marginTop="-10dp" />
<!--名称 - 在标签下面-->
<TextView
android:id="@+id/tv_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="@dimen/dp_5"
android:paddingRight="@dimen/dp_5"
android:singleLine="true"
android:textColor="@color/white"
android:textSize="@dimen/sp_10"
app:layout_constraintTop_toBottomOf="@id/iv_tag_type"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:text="麦位1"
tools:textColor="@color/color_FF333333" />
<!--心动值 - 在名称下面-->
<com.qxcm.moduleutil.widget.WheatCharmView
android:id="@+id/charm_view"
android:layout_width="@dimen/dp_52"
android:layout_height="@dimen/dp_12"
android:clipChildren="false"
android:clipToPadding="false"
android:visibility="visible"
app:layout_constraintTop_toBottomOf="@id/tv_name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<!--其他辅助视图保持不变-->
<ImageView
android:id="@+id/iv_sex"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@mipmap/common_ic_headportriat_base"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/riv"
app:layout_constraintEnd_toEndOf="@id/riv"
app:layout_constraintStart_toStartOf="@id/riv"
app:layout_constraintTop_toTopOf="@id/riv"
tools:visibility="visible" />
<View
android:id="@+id/view2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="@id/riv"
app:layout_constraintStart_toStartOf="@id/riv"
app:layout_constraintTop_toTopOf="@id/riv" />
<ImageView
android:id="@+id/iv_tag_boos"
android:layout_width="32dp"
android:layout_height="14dp"
android:src="@mipmap/room_ic_wheat_tag_boss"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/view2"
app:layout_constraintEnd_toEndOf="@id/riv"
app:layout_constraintStart_toStartOf="@id/riv"
tools:visibility="visible" />
<TextView
android:id="@+id/tv_time"
android:layout_width="@dimen/dp_35"
android:layout_height="17.5dp"
android:background="@mipmap/za_s"
android:gravity="center"
android:text="00:00"
android:textColor="@color/white"
android:textSize="@dimen/sp_9"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/riv"
app:layout_constraintEnd_toEndOf="@id/riv"
app:layout_constraintStart_toStartOf="@id/riv"
tools:visibility="visible" />
<View
android:id="@+id/view_riv_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="7dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/riv"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/cl_guide1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.2" />
<TextView
android:id="@+id/tv_time_pk"
android:layout_width="@dimen/dp_35"
android:layout_height="17.5dp"
android:background="@mipmap/za_s"
android:layout_marginBottom="@dimen/dp_5"
android:gravity="center"
android:text="00:00"
android:textColor="@color/white"
android:textSize="@dimen/sp_9"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="@id/riv"
app:layout_constraintStart_toStartOf="@id/riv"
app:layout_constraintTop_toBottomOf="@id/tv_name"
tools:visibility="visible" />
<ImageView
android:id="@+id/iv_shutup"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="4dp"
android:src="@mipmap/room_ic_wheat_shutup"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="@id/riv"
app:layout_constraintHeight_percent="0.05"
app:layout_constraintStart_toStartOf="@id/riv"
app:layout_constraintWidth_percent="0.05"
tools:visibility="visible" />
<com.qxcm.moduleutil.widget.ExpressionImgView
android:id="@+id/iv_face"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/riv"
app:layout_constraintEnd_toEndOf="@id/riv"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="@id/riv"
app:layout_constraintTop_toTopOf="@id/riv"
app:layout_constraintVertical_bias="0.0" />
<ImageView
android:id="@+id/iv_gift"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/iv_maozi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_10"
android:layout_marginTop="@dimen/dp_1"
android:scaleType="centerInside"
android:src="@mipmap/ic_room_huangguan"
android:visibility="gone"
app:layout_constraintStart_toStartOf="@id/iv_frame"
app:layout_constraintTop_toTopOf="@id/iv_frame"
tools:visibility="visible" />
<TextView
android:id="@+id/tv_no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/ic_room_xq_wno_male"
android:gravity="center"
android:text="1"
android:textColor="#fff"
android:textSize="@dimen/sp_10"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/iv_frame"
app:layout_constraintEnd_toEndOf="@id/riv"
app:layout_constraintStart_toStartOf="@id/riv"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>