修改BUg,修改盲盒转盘BUG
This commit is contained in:
@@ -22,13 +22,13 @@ public class NewsPresenter extends BasePresenter<NewsContacts.View> implements N
|
|||||||
@Override
|
@Override
|
||||||
public void onSubscribe(Disposable d) {
|
public void onSubscribe(Disposable d) {
|
||||||
addDisposable(d);
|
addDisposable(d);
|
||||||
MvpRef.get().finishRefresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNext(List<NewsMessageList> newsMessageLists) {
|
public void onNext(List<NewsMessageList> newsMessageLists) {
|
||||||
MvpRef.get().showNews(newsMessageLists);
|
MvpRef.get().showNews(newsMessageLists);
|
||||||
|
MvpRef.get().finishRefresh();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ public class OfficialNoticeActivity extends BaseMvpActivity<NewsPresenter, Activ
|
|||||||
private int page = 1;
|
private int page = 1;
|
||||||
private BaseQuickAdapter<NewsMessageList, BaseViewHolder> mAdapter;
|
private BaseQuickAdapter<NewsMessageList, BaseViewHolder> mAdapter;
|
||||||
private String type;
|
private String type;
|
||||||
|
private boolean isRefresh = true; // 添加标志位区分刷新和加载更多
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initData() {
|
protected void initData() {
|
||||||
@@ -48,12 +49,14 @@ public class OfficialNoticeActivity extends BaseMvpActivity<NewsPresenter, Activ
|
|||||||
@Override
|
@Override
|
||||||
public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
|
public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
|
||||||
page++;
|
page++;
|
||||||
|
isRefresh = false; // 设置为加载更多模式
|
||||||
MvpPre.getMessagetitle(type, page + "", "10");
|
MvpPre.getMessagetitle(type, page + "", "10");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRefresh(@NonNull RefreshLayout refreshLayout) {
|
public void onRefresh(@NonNull RefreshLayout refreshLayout) {
|
||||||
page = 1;
|
page = 1;
|
||||||
|
isRefresh = true; // 设置为刷新模式
|
||||||
MvpPre.getMessagetitle(type, page + "", "10");
|
MvpPre.getMessagetitle(type, page + "", "10");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -124,7 +127,15 @@ public class OfficialNoticeActivity extends BaseMvpActivity<NewsPresenter, Activ
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showNews(List<NewsMessageList> newsList) {
|
public void showNews(List<NewsMessageList> newsList) {
|
||||||
mAdapter.setNewData(newsList);
|
if (isRefresh) {
|
||||||
|
// 下拉刷新
|
||||||
|
mAdapter.setNewData(newsList);
|
||||||
|
} else {
|
||||||
|
// 上拉加载更多
|
||||||
|
if (newsList!=null) {
|
||||||
|
mAdapter.addData(newsList);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -434,8 +434,8 @@ public class CommonAppContext extends MultiDexApplication implements Applicatio
|
|||||||
// startService(mqttServiceIntent);
|
// startService(mqttServiceIntent);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// mqttConnect=MqttConnect.getInstance(this,"tcp://1.13.181.248","android-"+ MqttClient.generateClientId());
|
mqttConnect=MqttConnect.getInstance(this,"tcp://1.13.181.248","android-"+ MqttClient.generateClientId());
|
||||||
mqttConnect=MqttConnect.getInstance(this,"tcp://62.234.12.147","android-"+ MqttClient.generateClientId());
|
// mqttConnect=MqttConnect.getInstance(this,"tcp://62.234.12.147","android-"+ MqttClient.generateClientId());
|
||||||
mqttConnect.mqttClient();
|
mqttConnect.mqttClient();
|
||||||
|
|
||||||
// 每次启动应用时重置状态
|
// 每次启动应用时重置状态
|
||||||
|
|||||||
@@ -196,13 +196,13 @@ public class GiftLotteryDialog extends BaseMvpDialogFragment<GiftLotteryPresente
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void stopPlay() {
|
private void stopPlay() {
|
||||||
if (mediaPlayer != null && player != null) {
|
if ( player != null) {
|
||||||
player.stop();
|
player.stop();
|
||||||
player.reset();
|
player.reset();
|
||||||
player = null;
|
player = null;
|
||||||
mediaPlayer.stop();
|
// mediaPlayer.stop();
|
||||||
mediaPlayer.reset();
|
// mediaPlayer.reset();
|
||||||
mediaPlayer = null;
|
// mediaPlayer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -607,6 +607,7 @@ public class GiftLotteryDialog extends BaseMvpDialogFragment<GiftLotteryPresente
|
|||||||
|
|
||||||
// 停止之前的定时器
|
// 停止之前的定时器
|
||||||
stopFastAnimate();
|
stopFastAnimate();
|
||||||
|
stopPlay();
|
||||||
Log.e("isOpenSound===", "isOpenSound111" + isOpenSound);
|
Log.e("isOpenSound===", "isOpenSound111" + isOpenSound);
|
||||||
if (isOpenSound) {
|
if (isOpenSound) {
|
||||||
// 假设此处有播放音乐的逻辑
|
// 假设此处有播放音乐的逻辑
|
||||||
@@ -709,17 +710,17 @@ public class GiftLotteryDialog extends BaseMvpDialogFragment<GiftLotteryPresente
|
|||||||
}
|
}
|
||||||
|
|
||||||
private MediaPlayer player;
|
private MediaPlayer player;
|
||||||
MediaPlayer mediaPlayer;
|
// MediaPlayer mediaPlayer;
|
||||||
|
|
||||||
// 播放音频的方法
|
// 播放音频的方法
|
||||||
private void playSound(String fileName) {
|
private void playSound(String fileName) {
|
||||||
try {
|
try {
|
||||||
mediaPlayer = getPlayer(fileName);
|
player = getPlayer(fileName);
|
||||||
if (mediaPlayer != null) {
|
if (player != null) {
|
||||||
if (mediaPlayer.isPlaying()) {
|
if (player.isPlaying()) {
|
||||||
mediaPlayer.seekTo(0);
|
player.seekTo(0);
|
||||||
}
|
}
|
||||||
mediaPlayer.start();
|
player.start();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -737,15 +738,17 @@ public class GiftLotteryDialog extends BaseMvpDialogFragment<GiftLotteryPresente
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
AssetFileDescriptor afd = getContext().getAssets().openFd(fileName);
|
|
||||||
player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
|
|
||||||
player.prepare();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// else {
|
||||||
|
// try {
|
||||||
|
// AssetFileDescriptor afd = getContext().getAssets().openFd(fileName);
|
||||||
|
// mediaPlayer = new MediaPlayer();
|
||||||
|
// mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
|
||||||
|
// mediaPlayer.prepare();
|
||||||
|
// } catch (IOException e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -926,11 +929,9 @@ public class GiftLotteryDialog extends BaseMvpDialogFragment<GiftLotteryPresente
|
|||||||
startFastAnimate();
|
startFastAnimate();
|
||||||
} else {
|
} else {
|
||||||
if (isOpenSound) {//音效
|
if (isOpenSound) {//音效
|
||||||
isDrawing = false;
|
|
||||||
playSound("xuanz.mp3");
|
playSound("xuanz.mp3");
|
||||||
} else {
|
|
||||||
isDrawing = false;
|
|
||||||
}
|
}
|
||||||
|
isDrawing = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
isDrawing = false;
|
isDrawing = false;
|
||||||
|
|||||||
@@ -27,11 +27,11 @@ public class EnvironmentPrefs {
|
|||||||
|
|
||||||
// 获取当前选择的环境,默认为 PRODUCTION
|
// 获取当前选择的环境,默认为 PRODUCTION
|
||||||
public EnvironmentEnum getSelectedEnvironment() {
|
public EnvironmentEnum getSelectedEnvironment() {
|
||||||
String envName = sharedPreferences.getString(KEY_ENV, EnvironmentEnum.PRODUCTION.name());
|
String envName = sharedPreferences.getString(KEY_ENV, EnvironmentEnum.TEST.name());
|
||||||
try {
|
try {
|
||||||
return EnvironmentEnum.valueOf(envName);
|
return EnvironmentEnum.valueOf(envName);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
return EnvironmentEnum.PRODUCTION; // 出错时默认返回生产环境
|
return EnvironmentEnum.TEST; // 出错时默认返回生产环境
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,317 +1,250 @@
|
|||||||
package com.xscm.moduleutil.view;
|
package com.xscm.moduleutil.view;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.PorterDuff;
|
||||||
|
import android.graphics.PorterDuffXfermode;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.RectF;
|
||||||
import android.graphics.drawable.GradientDrawable;
|
import android.graphics.drawable.GradientDrawable;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.Gravity;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.widget.AppCompatImageView;
|
|
||||||
|
|
||||||
|
import com.bumptech.glide.Glide;
|
||||||
import com.xscm.moduleutil.R;
|
import com.xscm.moduleutil.R;
|
||||||
|
import com.xscm.moduleutil.bean.UserInfo;
|
||||||
import com.xscm.moduleutil.bean.blindboxwheel.BlindBoxBean;
|
import com.xscm.moduleutil.bean.blindboxwheel.BlindBoxBean;
|
||||||
import com.xscm.moduleutil.utils.ImageUtils;
|
import com.xscm.moduleutil.utils.ImageUtils;
|
||||||
import com.xscm.moduleutil.widget.GifAvatarOvalView;
|
import com.xscm.moduleutil.widget.GifAvatarOvalView;
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户信息展示View(修复装饰图不显示 + 标签调整至头像下方-10dp)
|
|
||||||
*/
|
|
||||||
public class QXMeetUserView extends RelativeLayout {
|
public class QXMeetUserView extends RelativeLayout {
|
||||||
private static final String TAG = "QXMeetUserView";
|
|
||||||
// 1. 装饰图与头像配置(确保装饰图露出,修复不显示问题)
|
|
||||||
private static final int DRESS_EXCEED_AVATAR_DP = 4; // 装饰图四周露4dp,保留装饰效果
|
|
||||||
private static final int MIN_DRESS_SIZE_DP = 50; // 装饰图最小尺寸,避免过小导致不显示
|
|
||||||
private static final int MAX_DRESS_SIZE_DP = 100; // 限制最大尺寸,防止布局失衡
|
|
||||||
// 2. 标签与名称配置(核心:标签偏移改为-10dp,在头像下方)
|
|
||||||
private static final int TAG_NAME_SPACING_DP = 3; // 标签与名称间距,防止重叠
|
|
||||||
private static final int TAG_HEIGHT_DP = 16; // 标签固定高度
|
|
||||||
private static final int NAME_BOTTOM_MARGIN_DP = 8; // 名称与父布局底部间距
|
|
||||||
private static final int TAG_BOTTOM_OFFSET_DP = -10; // 标签相对头像底部向下偏移10dp(核心调整)
|
|
||||||
|
|
||||||
private GifAvatarOvalView ivAvatar; // 头像(中层)
|
private GifAvatarOvalView headerImageView;
|
||||||
private ImageView ivAvatarDress; // 装饰图(底层,确保最下方显示)
|
private ImageView dressImageView;
|
||||||
private TextView tvTag; // 标签(顶层,在头像下方)
|
private TextView tagLabel;
|
||||||
private TextView tvName; // 名称(顶层,在标签下方)
|
private TextView nameLabel;
|
||||||
|
|
||||||
private boolean isLuckUser;
|
private boolean isLuckUser;
|
||||||
private BlindBoxBean.xlhUser userModel;
|
private Object model; // 这里用 Object 代替 QXUserModel
|
||||||
|
|
||||||
// 构造方法
|
|
||||||
public QXMeetUserView(Context context) {
|
public QXMeetUserView(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
initViewHierarchy(context);
|
initSubviews(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QXMeetUserView(Context context, @Nullable AttributeSet attrs) {
|
public QXMeetUserView(Context context, @Nullable AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
initViewHierarchy(context);
|
initSubviews(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QXMeetUserView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
public QXMeetUserView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
initViewHierarchy(context);
|
initSubviews(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void initSubviews(Context context) {
|
||||||
* 初始化视图层级(核心:严格按“底层→中层→顶层”顺序,确保装饰图在最下)
|
setClipChildren(false);
|
||||||
*/
|
|
||||||
private void initViewHierarchy(Context context) {
|
|
||||||
setClipChildren(false); // 允许子View超出父布局,避免装饰图边缘被裁剪
|
|
||||||
setClipToPadding(false);
|
setClipToPadding(false);
|
||||||
setWillNotDraw(false);
|
|
||||||
initAvatar(context); // 2. 再加头像,覆盖装饰图中间
|
|
||||||
// 层级顺序:1.装饰图(底层)→2.头像(中层)→3.名称→4.标签(顶层)
|
|
||||||
initAvatarDress(context); // 1. 先加装饰图,确保在最底层
|
|
||||||
|
|
||||||
initName(context); // 3. 加名称(用于标签定位)
|
// 创建头像图片视图
|
||||||
initTag(context); // 4. 最后加标签,确保在顶层
|
headerImageView = new GifAvatarOvalView(context);
|
||||||
|
headerImageView.setScaleType(ImageView.ScaleType.FIT_CENTER); // 添加这一行
|
||||||
|
// headerImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||||
|
// headerImageView.setImageResource(R.mipmap.default_avatar);
|
||||||
|
|
||||||
// 强制层级确认(避免渲染异常,装饰图不调用bringChildToFront,保持最底层)
|
int headerSize = getMeasuredWidth() - dpToPx(18); // self.width-9*2
|
||||||
bringChildToFront(ivAvatar); // 中层:头像在装饰图之上
|
LayoutParams headerParams = new LayoutParams(headerSize, headerSize);
|
||||||
bringChildToFront(tvName); // 顶层下层:名称在头像之上
|
headerParams.setMargins(0, 10, 0, 0);
|
||||||
bringChildToFront(tvTag); // 顶层上层:标签在名称之上
|
headerParams.addRule(CENTER_IN_PARENT);
|
||||||
}
|
// 将头像添加到装饰视图之上
|
||||||
|
addView(headerImageView, headerParams);
|
||||||
|
|
||||||
/**
|
// 创建装饰图片视图
|
||||||
* 初始化装饰图(修复不显示:优化ScaleType+确保尺寸足够)
|
dressImageView = new ImageView(context);
|
||||||
*/
|
dressImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||||
private void initAvatarDress(Context context) {
|
dressImageView.setImageResource(R.mipmap.xlh_image);
|
||||||
ivAvatarDress = new ImageView(context);
|
|
||||||
// 修复:若装饰图是边框/框架类资源(如圆形外框),用CENTER(不缩放,完整显示)
|
|
||||||
ivAvatarDress.setScaleType(ImageView.ScaleType.CENTER);
|
|
||||||
ivAvatarDress.setImageResource(R.mipmap.xlh_image); // 确保资源引用正确
|
|
||||||
|
|
||||||
// 初始尺寸:基于装饰图最小尺寸,避免初始过小导致不显示
|
LayoutParams dressParams = new LayoutParams(
|
||||||
int initDressSize = dp2px(MIN_DRESS_SIZE_DP);
|
LayoutParams.MATCH_PARENT,
|
||||||
LayoutParams dressParams = new LayoutParams(initDressSize, initDressSize);
|
LayoutParams.MATCH_PARENT
|
||||||
dressParams.addRule(CENTER_HORIZONTAL); // 与头像水平居中对齐
|
|
||||||
dressParams.addRule(CENTER_VERTICAL); // 暂用垂直居中,后续onLayout精准调整
|
|
||||||
addView(ivAvatarDress, dressParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化头像(中层:尺寸=装饰图尺寸-2*超出尺寸,确保装饰图露出)
|
|
||||||
*/
|
|
||||||
private void initAvatar(Context context) {
|
|
||||||
ivAvatar = new GifAvatarOvalView(context);
|
|
||||||
ivAvatar.setId(View.generateViewId()); // 生成唯一ID,用于标签定位
|
|
||||||
ivAvatar.setScaleType(AppCompatImageView.ScaleType.CENTER_CROP); // 头像填满容器,无变形
|
|
||||||
ivAvatar.setImageResource(R.mipmap.default_avatar);
|
|
||||||
|
|
||||||
// 初始尺寸:装饰图尺寸 - 2*超出尺寸(确保四周露4dp装饰图)
|
|
||||||
int initDressSize = dp2px(MIN_DRESS_SIZE_DP);
|
|
||||||
int initAvatarSize = initDressSize - dp2px(DRESS_EXCEED_AVATAR_DP * 2);
|
|
||||||
LayoutParams avatarParams = new LayoutParams(initAvatarSize, initAvatarSize);
|
|
||||||
avatarParams.addRule(CENTER_HORIZONTAL); // 与装饰图水平对齐
|
|
||||||
avatarParams.addRule(CENTER_VERTICAL); // 暂用垂直居中,后续onLayout精准调整
|
|
||||||
addView(ivAvatar, avatarParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化名称(固定底部定位,给标签预留足够空间)
|
|
||||||
*/
|
|
||||||
private void initName(Context context) {
|
|
||||||
tvName = new TextView(context);
|
|
||||||
tvName.setId(View.generateViewId()); // 生成ID,用于标签ABOVE约束
|
|
||||||
tvName.setTextColor(0xFFFFFFFF);
|
|
||||||
tvName.setTextSize(12);
|
|
||||||
tvName.setText("虚位以待");
|
|
||||||
tvName.setGravity(Gravity.CENTER);
|
|
||||||
tvName.setMaxWidth(dp2px(100)); // 限制最大宽度,避免名称过长换行
|
|
||||||
tvName.setSingleLine(true); // 强制单行,避免高度异常
|
|
||||||
|
|
||||||
LayoutParams nameParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
|
||||||
nameParams.addRule(CENTER_HORIZONTAL); // 与头像/装饰图水平对齐
|
|
||||||
nameParams.addRule(ALIGN_PARENT_BOTTOM); // 固定在父布局底部
|
|
||||||
nameParams.bottomMargin = dp2px(NAME_BOTTOM_MARGIN_DP); // 与底部保持间距
|
|
||||||
addView(tvName, nameParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化标签(核心:调整至头像下方-10dp,水平居中)
|
|
||||||
*/
|
|
||||||
private void initTag(Context context) {
|
|
||||||
tvTag = new TextView(context);
|
|
||||||
tvTag.setTextColor(0xFFFFE554);
|
|
||||||
tvTag.setTextSize(12);
|
|
||||||
tvTag.setGravity(Gravity.CENTER);
|
|
||||||
tvTag.setText("房主");
|
|
||||||
tvTag.setHeight(dp2px(TAG_HEIGHT_DP)); // 固定标签高度,避免挤压名称
|
|
||||||
tvTag.setBackground(getRoundedBg(0xFF8D6F28, dp2px(8)));
|
|
||||||
|
|
||||||
LayoutParams tagParams = new LayoutParams(
|
|
||||||
dp2px(45), // 标签固定宽度
|
|
||||||
dp2px(TAG_HEIGHT_DP) // 标签固定高度
|
|
||||||
);
|
);
|
||||||
tagParams.addRule(CENTER_HORIZONTAL); // 与头像水平对齐
|
addView(dressImageView, dressParams);
|
||||||
tagParams.addRule(ALIGN_BOTTOM, ivAvatar.getId()); // 基于头像底部定位
|
|
||||||
tagParams.bottomMargin = dp2px(TAG_BOTTOM_OFFSET_DP); // 向下偏移10dp(在头像下方)
|
// 创建标签标签
|
||||||
tagParams.addRule(ABOVE, tvName.getId()); // 标签在名称上方,防止重叠
|
tagLabel = new TextView(context);
|
||||||
tagParams.setMargins(0, 0, 0, dp2px(TAG_NAME_SPACING_DP)); // 与名称保持3dp间距
|
tagLabel.setTextColor(0xFFFFE554); // RGB16(0xFFE554)
|
||||||
addView(tvTag, tagParams);
|
tagLabel.setTextSize(12);
|
||||||
|
tagLabel.setGravity(android.view.Gravity.CENTER);
|
||||||
|
tagLabel.setBackground(getRoundedRectBackground(0xFF8D6F28, dpToPx(8))); // 默认房主背景色
|
||||||
|
|
||||||
|
LayoutParams tagParams = new LayoutParams(dpToPx(45), dpToPx(16));
|
||||||
|
tagParams.addRule(CENTER_HORIZONTAL);
|
||||||
|
// 需要在测量完成后设置底部位置
|
||||||
|
addView(tagLabel, tagParams);
|
||||||
|
|
||||||
|
// 创建名称标签
|
||||||
|
nameLabel = new TextView(context);
|
||||||
|
nameLabel.setTextColor(0xFFFFFFFF); // RGB16(0xffffff)
|
||||||
|
nameLabel.setTextSize(12);
|
||||||
|
nameLabel.setText("虚位以待");
|
||||||
|
nameLabel.setGravity(android.view.Gravity.CENTER);
|
||||||
|
|
||||||
|
LayoutParams nameParams = new LayoutParams(
|
||||||
|
LayoutParams.WRAP_CONTENT,
|
||||||
|
LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
nameParams.addRule(CENTER_HORIZONTAL);
|
||||||
|
nameParams.addRule(ALIGN_PARENT_BOTTOM);
|
||||||
|
addView(nameLabel, nameParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 测量阶段(确保装饰图优先获取尺寸,避免被挤压不显示)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
// 先测量子View,获取名称、标签基础尺寸
|
|
||||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
|
||||||
if (ivAvatar == null || ivAvatarDress == null || tvTag == null || tvName == null) return;
|
// 确保在测量时设置正确的头像尺寸
|
||||||
|
if (headerImageView != null) {
|
||||||
// 1. 计算装饰图最终尺寸(优先级:父布局宽度限制→最大尺寸→最小尺寸)
|
int headerSize = getMeasuredWidth() - dpToPx(18); // width - 9dp * 2
|
||||||
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
|
LayoutParams headerParams = (LayoutParams) headerImageView.getLayoutParams();
|
||||||
int maxDressSize = dp2px(MAX_DRESS_SIZE_DP);
|
if (headerParams != null) {
|
||||||
int minDressSize = dp2px(MIN_DRESS_SIZE_DP);
|
headerParams.width = headerSize;
|
||||||
int finalDressSize = Math.min(
|
headerParams.height = headerSize;
|
||||||
Math.max(parentWidth * 8 / 10, minDressSize), // 父布局宽度80%,避免撑满
|
headerParams.leftMargin = dpToPx(9);
|
||||||
maxDressSize
|
headerParams.topMargin = dpToPx(9);
|
||||||
);
|
headerImageView.setLayoutParams(headerParams);
|
||||||
|
}
|
||||||
// 2. 计算头像最终尺寸(严格依赖装饰图,确保装饰图露出)
|
}
|
||||||
int dressExceed = dp2px(DRESS_EXCEED_AVATAR_DP);
|
|
||||||
int finalAvatarSize = finalDressSize - (dressExceed * 2);
|
|
||||||
finalAvatarSize = Math.max(finalAvatarSize, dp2px(10)); // 兜底最小尺寸,避免过小
|
|
||||||
|
|
||||||
// 3. 更新装饰图和头像尺寸(先更装饰图,确保其有足够空间)
|
|
||||||
updateViewSize(ivAvatarDress, finalDressSize, finalDressSize);
|
|
||||||
updateViewSize(ivAvatar, finalAvatarSize, finalAvatarSize);
|
|
||||||
|
|
||||||
// 4. 计算父布局最小高度(容纳所有元素,避免装饰图/标签被裁)
|
|
||||||
int tagHeight = dp2px(TAG_HEIGHT_DP);
|
|
||||||
int nameHeight = tvName.getMeasuredHeight();
|
|
||||||
int tagNameSpacing = dp2px(TAG_NAME_SPACING_DP);
|
|
||||||
int nameBottomMargin = dp2px(NAME_BOTTOM_MARGIN_DP);
|
|
||||||
int minParentHeight = finalDressSize + tagHeight + tagNameSpacing + nameHeight + nameBottomMargin;
|
|
||||||
|
|
||||||
// 确定父布局最终尺寸(高度取测量值与最小高度最大值,避免挤压)
|
|
||||||
int finalParentWidth = parentWidth;
|
|
||||||
int finalParentHeight = Math.max(MeasureSpec.getSize(heightMeasureSpec), minParentHeight);
|
|
||||||
setMeasuredDimension(finalParentWidth, finalParentHeight);
|
|
||||||
|
|
||||||
// 重新测量子View,确保所有尺寸生效
|
|
||||||
measureChildren(
|
|
||||||
MeasureSpec.makeMeasureSpec(finalParentWidth, MeasureSpec.EXACTLY),
|
|
||||||
MeasureSpec.makeMeasureSpec(finalParentHeight, MeasureSpec.EXACTLY)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 布局阶段(精准定位,确保装饰图完整显示、标签在头像下方-10dp)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||||
super.onLayout(changed, l, t, r, b);
|
super.onLayout(changed, l, t, r, b);
|
||||||
|
|
||||||
if (!changed || ivAvatar == null || ivAvatarDress == null || tvTag == null || tvName == null) {
|
// 在布局完成后设置标签的位置(在头像底部-8的位置)
|
||||||
return;
|
if (changed && headerImageView != null && tagLabel != null) {
|
||||||
}
|
int tagTop = headerImageView.getBottom() - dpToPx(8);
|
||||||
|
int tagLeft = (getWidth() - tagLabel.getWidth()) / 2;
|
||||||
// 1. 布局装饰图(底层,水平居中,垂直预留标签/名称空间)
|
tagLabel.layout(tagLeft, tagTop, tagLeft + tagLabel.getWidth(), tagTop + tagLabel.getHeight());
|
||||||
int dressWidth = ivAvatarDress.getMeasuredWidth();
|
|
||||||
int dressHeight = ivAvatarDress.getMeasuredHeight();
|
|
||||||
int parentWidth = getMeasuredWidth();
|
|
||||||
int parentHeight = getMeasuredHeight();
|
|
||||||
int dressLeft = (parentWidth - dressWidth) / 2; // 水平居中,避免左右偏移
|
|
||||||
// 垂直位置:父布局上半部分,预留标签+名称空间,避免装饰图靠下被裁
|
|
||||||
int dressTop = (parentHeight - (dressHeight + dp2px(TAG_HEIGHT_DP + TAG_NAME_SPACING_DP))) / 2;
|
|
||||||
dressTop = Math.max(dressTop, 0); // 兜底,避免装饰图顶部超出父布局
|
|
||||||
ivAvatarDress.layout(dressLeft, dressTop, dressLeft + dressWidth, dressTop + dressHeight);
|
|
||||||
|
|
||||||
// 2. 布局头像(中层,在装饰图正中间,四周露4dp装饰图)
|
|
||||||
int avatarWidth = ivAvatar.getMeasuredWidth();
|
|
||||||
int avatarHeight = ivAvatar.getMeasuredHeight();
|
|
||||||
int avatarLeft = dressLeft + dressExceed;
|
|
||||||
int avatarTop = dressTop + dressExceed;
|
|
||||||
ivAvatar.layout(avatarLeft, avatarTop, avatarLeft + avatarWidth, avatarTop + avatarHeight);
|
|
||||||
|
|
||||||
// 3. 布局标签(顶层,在头像下方-10dp,水平居中)
|
|
||||||
int tagWidth = tvTag.getMeasuredWidth();
|
|
||||||
int tagHeight = tvTag.getMeasuredHeight();
|
|
||||||
int tagLeft = (parentWidth - tagWidth) / 2; // 与头像水平对齐
|
|
||||||
// 垂直位置:头像底部 + 向下偏移10dp(TAG_BOTTOM_OFFSET_DP=-10)
|
|
||||||
int tagTop = avatarTop + avatarHeight + dp2px(TAG_BOTTOM_OFFSET_DP);
|
|
||||||
tvTag.layout(tagLeft, tagTop, tagLeft + tagWidth, tagTop + tagHeight);
|
|
||||||
|
|
||||||
// 4. 布局名称(顶层,在标签下方,保持3dp间距)
|
|
||||||
int nameWidth = tvName.getMeasuredWidth();
|
|
||||||
int nameHeight = tvName.getMeasuredHeight();
|
|
||||||
int nameLeft = (parentWidth - nameWidth) / 2; // 与标签水平对齐
|
|
||||||
int nameTop = tagTop + tagHeight + dp2px(TAG_NAME_SPACING_DP); // 与标签保持间距
|
|
||||||
// 兜底:避免名称底部超出父布局
|
|
||||||
nameTop = Math.min(nameTop, parentHeight - nameHeight - dp2px(NAME_BOTTOM_MARGIN_DP));
|
|
||||||
tvName.layout(nameLeft, nameTop, nameLeft + nameWidth, nameTop + nameHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 辅助方法:更新View尺寸(避免重复代码)
|
|
||||||
*/
|
|
||||||
private void updateViewSize(View view, int width, int height) {
|
|
||||||
LayoutParams params = (LayoutParams) view.getLayoutParams();
|
|
||||||
if (params != null) {
|
|
||||||
params.width = width;
|
|
||||||
params.height = height;
|
|
||||||
view.setLayoutParams(params);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ====================== 原有业务逻辑(保持不变) ======================
|
|
||||||
public void setIsLuckUser(boolean isLuckUser) {
|
public void setIsLuckUser(boolean isLuckUser) {
|
||||||
this.isLuckUser = isLuckUser;
|
this.isLuckUser = isLuckUser;
|
||||||
|
|
||||||
if (isLuckUser) {
|
if (isLuckUser) {
|
||||||
tvTag.setTextColor(0xFFFFFFFF);
|
tagLabel.setTextColor(0xFFFFFFFF); // RGB16(0xffffff)
|
||||||
tvTag.setBackground(getRoundedBg(0xFF6C49E4, dp2px(8)));
|
tagLabel.setBackground(getRoundedRectBackground(0xFF6C49E4, dpToPx(8))); // RGB16(0x6C49E4)
|
||||||
tvTag.setText("幸运者");
|
// tagLabel.setBackgroundColor(getResources().getColor(R.color.color_FF6C49E4)); // RGB16(0x6C49E4)
|
||||||
|
tagLabel.setText("幸运者");
|
||||||
} else {
|
} else {
|
||||||
tvTag.setTextColor(0xFFFFE554);
|
tagLabel.setTextColor(0xFFFFE554); // RGB16(0xFFE554)
|
||||||
tvTag.setBackground(getRoundedBg(0xFF8D6F28, dp2px(8)));
|
tagLabel.setBackground(getRoundedRectBackground(0xFF8D6F28, dpToPx(8))); // RGB16(0x8D6F28)
|
||||||
tvTag.setText("房主");
|
// tagLabel.setBackgroundColor(getResources().getColor(R.color.color_FF8D6F28)); // RGB16(0x6C49E4)
|
||||||
|
|
||||||
|
tagLabel.setText("房主");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setModel(BlindBoxBean.xlhUser model) {
|
public void setModel(BlindBoxBean.xlhUser model) {
|
||||||
this.userModel = model;
|
this.model = model;
|
||||||
if (model != null) {
|
// 这里需要根据您的 QXUserModel 类来实现具体逻辑
|
||||||
ImageUtils.loadHeadCC(model.getAvatar(), ivAvatar);
|
if (model instanceof BlindBoxBean.xlhUser) {
|
||||||
tvName.setText(model.getNickname() != null ? model.getNickname() : "虚位以待");
|
BlindBoxBean.xlhUser userModel = (BlindBoxBean.xlhUser) model;
|
||||||
} else {
|
|
||||||
resetView();
|
// 使用图片加载库加载头像
|
||||||
|
// Glide.with(getContext()).load(userModel.getAvatar()).into(headerImageView);
|
||||||
|
ImageUtils.loadHeadCC(userModel.getAvatar(), headerImageView);
|
||||||
|
nameLabel.setText(userModel.getNickname());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetView() {
|
public void resetView() {
|
||||||
if (ivAvatar != null) {
|
headerImageView.setImageResource(R.mipmap.default_avatar);
|
||||||
ivAvatar.setImageResource(R.mipmap.default_avatar);
|
nameLabel.setText("虚位以待");
|
||||||
}
|
|
||||||
if (tvName != null) {
|
|
||||||
tvName.setText("虚位以待");
|
|
||||||
}
|
|
||||||
if (tvTag != null) {
|
|
||||||
tvTag.setText("房主");
|
|
||||||
tvTag.setTextColor(0xFFFFE554);
|
|
||||||
tvTag.setBackground(getRoundedBg(0xFF8D6F28, dp2px(8)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ====================== 工具方法(保持不变) ======================
|
// 创建圆角矩形背景
|
||||||
private GradientDrawable getRoundedBg(int color, float radius) {
|
private android.graphics.drawable.Drawable getRoundedRectBackground(int color, float radius) {
|
||||||
GradientDrawable drawable = new GradientDrawable();
|
GradientDrawable drawable = new GradientDrawable();
|
||||||
drawable.setColor(color);
|
drawable.setColor(color);
|
||||||
drawable.setCornerRadius(radius);
|
drawable.setCornerRadius(radius);
|
||||||
drawable.setPadding(dp2px(4), 0, dp2px(4), 0);
|
|
||||||
return drawable;
|
return drawable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int dp2px(int dp) {
|
// 辅助方法:dp 转 px
|
||||||
return Math.round(dp * getResources().getDisplayMetrics().density);
|
private int dpToPx(int dp) {
|
||||||
|
float density = getResources().getDisplayMetrics().density;
|
||||||
|
return Math.round(dp * density);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 临时变量:避免onLayout中重复计算dp值
|
// Getter 方法
|
||||||
private int dressExceed = dp2px(DRESS_EXCEED_AVATAR_DP);
|
public ImageView getHeaderImageView() {
|
||||||
|
return headerImageView;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageView getDressImageView() {
|
||||||
|
return dressImageView;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextView getTagLabel() {
|
||||||
|
return tagLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextView getNameLabel() {
|
||||||
|
return nameLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLuckUser() {
|
||||||
|
return isLuckUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getModel() {
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自定义圆形 ImageView
|
||||||
|
private static class RoundImageView extends androidx.appcompat.widget.AppCompatImageView {
|
||||||
|
public RoundImageView(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RoundImageView(Context context, @Nullable AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RoundImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas) {
|
||||||
|
// 创建圆形裁剪区域
|
||||||
|
int diameter = Math.min(getWidth(), getHeight());
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap(diameter, diameter, Bitmap.Config.ARGB_8888);
|
||||||
|
Canvas tempCanvas = new Canvas(bitmap);
|
||||||
|
|
||||||
|
// 绘制圆形
|
||||||
|
Paint paint = new Paint();
|
||||||
|
paint.setAntiAlias(true);
|
||||||
|
tempCanvas.drawCircle(diameter / 2f, diameter / 2f, diameter / 2f, paint);
|
||||||
|
|
||||||
|
// 设置混合模式
|
||||||
|
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
|
||||||
|
|
||||||
|
// 绘制原始图片
|
||||||
|
super.onDraw(tempCanvas);
|
||||||
|
|
||||||
|
// 将处理后的图片绘制到实际canvas
|
||||||
|
canvas.drawBitmap(bitmap, 0, 0, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -97,7 +97,8 @@
|
|||||||
<com.xscm.moduleutil.view.QXMeetUserView
|
<com.xscm.moduleutil.view.QXMeetUserView
|
||||||
android:id="@+id/gv_xyz"
|
android:id="@+id/gv_xyz"
|
||||||
android:layout_width="@dimen/dp_94"
|
android:layout_width="@dimen/dp_94"
|
||||||
android:layout_height="@dimen/dp_90"
|
android:layout_height="@dimen/dp_118"
|
||||||
|
android:layout_marginTop="@dimen/dp_21"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/iv_zyx"
|
app:layout_constraintEnd_toStartOf="@+id/iv_zyx"
|
||||||
android:layout_marginEnd="-13dp"
|
android:layout_marginEnd="-13dp"
|
||||||
android:translationY="@dimen/dp_78"
|
android:translationY="@dimen/dp_78"
|
||||||
|
|||||||
Reference in New Issue
Block a user