1:羽声新版本

This commit is contained in:
2025-10-24 17:55:15 +08:00
parent a809b02ebb
commit 529aae1fcf
821 changed files with 29411 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
package com.xscm.moduleutil.view;
import android.content.Context;
import android.util.AttributeSet;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat;
import com.xscm.moduleutil.R;
import org.jetbrains.annotations.NotNull;
/**
* 这是抢红包的自定义view
*/
public class CustomDialogView extends ConstraintLayout {
public CustomDialogView(@NonNull @NotNull Context context) {
super(context);
init();
}
public CustomDialogView(@NonNull @NotNull Context context, @Nullable @org.jetbrains.annotations.Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomDialogView(@NonNull @NotNull Context context, @Nullable @org.jetbrains.annotations.Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public CustomDialogView(@NonNull @NotNull Context context, @Nullable @org.jetbrains.annotations.Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
// 初始化视图
// 设置背景色
setBackground(ContextCompat.getDrawable(getContext(), R.drawable.bg_red_16_envel));
}
}

View File

@@ -0,0 +1,262 @@
package com.xscm.moduleutil.view;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.bumptech.glide.Glide;
import com.xscm.moduleutil.R;
import com.xscm.moduleutil.bean.GiftBean;
import com.xscm.moduleutil.bean.blindboxwheel.BlindBoxBean;
public class QXMeetGiftView extends RelativeLayout {
private TextView giftNameLabel;
private ImageView giftPriceBgView;
private Button giftCoin;
private ImageView bgImageView;
private ImageView giftBgImageView;
private ImageView giftImageView;
private boolean isLockGift;
private Object model; // 这里用 Object 代替 QXDrawGiftModel
public QXMeetGiftView(Context context) {
super(context);
initSubviews(context);
}
public QXMeetGiftView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initSubviews(context);
}
public QXMeetGiftView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initSubviews(context);
}
private void initSubviews(Context context) {
// 创建背景图片视图
bgImageView = new ImageView(context);
bgImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
bgImageView.setImageResource(R.drawable.ac_left_gift_bg);
LayoutParams bgParams = new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT
);
addView(bgImageView, bgParams);
// 创建礼物图片视图(圆形)
giftImageView = new ImageView(context);
giftImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
LayoutParams giftImageParams = new LayoutParams(
dpToPx(48), // 固定宽度
dpToPx(62) // 固定高度
);
giftImageParams.addRule(CENTER_IN_PARENT);
giftImageParams.topMargin = dpToPx(10);
addView(giftImageView, giftImageParams);
// 创建礼物背景光效视图
giftBgImageView = new ImageView(context);
giftBgImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
giftBgImageView.setImageResource(R.drawable.ac_lock_gift_light_bg);
giftBgImageView.setVisibility(View.GONE); // 初始隐藏
LayoutParams giftBgParams = new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT
);
addView(giftBgImageView, giftBgParams);
// 创建价格背景视图
giftPriceBgView = new ImageView(context);
giftPriceBgView.setImageResource(R.drawable.ac_meet_gift_name_bg);
LayoutParams priceBgParams = new LayoutParams(
LayoutParams.MATCH_PARENT,
dpToPx(15)
);
priceBgParams.addRule(CENTER_HORIZONTAL);
priceBgParams.addRule(ALIGN_PARENT_BOTTOM);
priceBgParams.bottomMargin = dpToPx(10); // 在名称标签上方
addView(giftPriceBgView, priceBgParams);
// 创建金币按钮
giftCoin = new Button(context);
giftCoin.setTextColor(0xFFC7BF62); // 使用直接的颜色值
// 设置按钮图标
Drawable coinDrawable = getResources().getDrawable(R.mipmap.jinb);
coinDrawable.setBounds(0, 0, dpToPx(1), dpToPx(1));
giftCoin.setCompoundDrawables(coinDrawable, null, null, null);
giftCoin.setTextSize(10);
giftCoin.setBackgroundColor(0x00000000); // 透明背景
LayoutParams coinParams = new LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
);
coinParams.addRule(CENTER_HORIZONTAL);
coinParams.addRule(ALIGN_PARENT_BOTTOM);
coinParams.bottomMargin = -dpToPx(2);
addView(giftCoin, coinParams);
// 创建礼物名称标签
giftNameLabel = new TextView(context);
giftNameLabel.setTextColor(0xFFFFFFFF);
giftNameLabel.setTextSize(12);
giftNameLabel.setGravity(android.view.Gravity.CENTER);
giftNameLabel.setSingleLine(true); // 设置为单行显示
giftNameLabel.setEllipsize(android.text.TextUtils.TruncateAt.END); // 超出部分用省略号表示
LayoutParams nameParams = new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT
);
nameParams.addRule(CENTER_HORIZONTAL);
nameParams.addRule(ALIGN_PARENT_BOTTOM);
nameParams.bottomMargin = dpToPx(1);
addView(giftNameLabel, nameParams);
// 调整视图层级 - 确保正确的层级关系
// 按添加顺序已经确定层级,最晚添加的在最上层
}
public void setIsLockGift(boolean isLockGift) {
this.isLockGift = isLockGift;
// 设置背景图片
int bgResource = isLockGift ?
R.drawable.ac_lock_gift_bg : R.drawable.ac_left_gift_bg;
bgImageView.setImageResource(bgResource);
// 显示/隐藏光效背景
giftBgImageView.setVisibility(isLockGift ? View.VISIBLE : View.GONE);
if (isLockGift) {
// 重新设置礼物图片的约束
LayoutParams params = (LayoutParams) giftImageView.getLayoutParams();
params.width = dpToPx(36);
params.height = dpToPx(36);
params.addRule(CENTER_IN_PARENT);
params.setMargins(0, 0, 0, 0);
giftImageView.setLayoutParams(params);
} else {
// 恢复原始约束
LayoutParams params = (LayoutParams) giftImageView.getLayoutParams();
params.width = LayoutParams.MATCH_PARENT;
params.height = LayoutParams.WRAP_CONTENT;
params.addRule(CENTER_IN_PARENT);
params.setMargins(dpToPx(6), dpToPx(6), dpToPx(6), 0);
giftImageView.setLayoutParams(params);
}
}
public void setModel(BlindBoxBean.GiveGift model) {
this.model = model;
// 这里需要根据您的 QXDrawGiftModel 类来实现具体逻辑
if (model instanceof BlindBoxBean.GiveGift) {
BlindBoxBean.GiveGift giftModel = (BlindBoxBean.GiveGift) model;
// 使用图片加载库加载图片
Glide.with(getContext()).load(giftModel.getBase_image()).into(giftImageView);
giftNameLabel.setText(giftModel.getGift_name());
giftCoin.setText(giftModel.getGift_price());
}
}
public void startAnimation() {
// 礼物图片顺时针旋转动画
RotateAnimation rotateAnimation = new RotateAnimation(
0, 360, // 从 0 度旋转到 360 度
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f
);
rotateAnimation.setDuration(3000); // 3 秒
rotateAnimation.setRepeatCount(Animation.INFINITE);
rotateAnimation.setRepeatMode(Animation.RESTART);
rotateAnimation.setInterpolator(getContext(), android.R.anim.linear_interpolator);
giftImageView.startAnimation(rotateAnimation);
// 光效背景逆时针旋转动画
RotateAnimation rotateAnimation1 = new RotateAnimation(
0, -360, // 从 0 度旋转到 -360 度
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f
);
rotateAnimation1.setDuration(3000); // 3 秒
rotateAnimation1.setRepeatCount(Animation.INFINITE);
rotateAnimation1.setRepeatMode(Animation.RESTART);
rotateAnimation1.setInterpolator(getContext(), android.R.anim.linear_interpolator);
giftBgImageView.startAnimation(rotateAnimation1);
}
public void resetAnimation() {
giftImageView.clearAnimation();
giftBgImageView.clearAnimation();
}
public void stopAnimation() {
giftImageView.clearAnimation();
giftBgImageView.clearAnimation();
}
// 辅助方法dp 转 px
private int dpToPx(int dp) {
float density = getResources().getDisplayMetrics().density;
return Math.round(dp * density);
}
// 缩放宽度方法(对应 ScaleWidth
private int scaleWidth(int value) {
// 这里需要根据您的缩放逻辑实现
// 通常可以根据屏幕密度进行缩放
float scale = getResources().getDisplayMetrics().density;
return (int) (value * scale);
}
// Getter 方法
public TextView getGiftNameLabel() {
return giftNameLabel;
}
public ImageView getGiftPriceBgView() {
return giftPriceBgView;
}
public Button getGiftCoin() {
return giftCoin;
}
public ImageView getBgImageView() {
return bgImageView;
}
public ImageView getGiftBgImageView() {
return giftBgImageView;
}
public ImageView getGiftImageView() {
return giftImageView;
}
public boolean isLockGift() {
return isLockGift;
}
public Object getModel() {
return model;
}
}

View File

@@ -0,0 +1,332 @@
package com.xscm.moduleutil.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.GradientDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.xscm.moduleutil.R;
import com.xscm.moduleutil.bean.blindboxwheel.BlindBoxBean;
import com.xscm.moduleutil.utils.ImageUtils;
import com.xscm.moduleutil.widget.GifAvatarOvalView;
public class QXMeetUserView extends RelativeLayout {
private static final String TAG = "QXMeetUserView";
private GifAvatarOvalView headerImageView; // 头像
private ImageView dressImageView; // 装饰图
private TextView tagLabel; // 标签
private TextView nameLabel; // 名称
// 布局属性变量
private int avatarSize; // 头像大小
private int dressSize; // 装饰图大小
private float nameTextSize; // 名字字体大小
private int nameTextColor; // 名字颜色
private float tagTextSize; // 标签字体大小
private int tagTextColor; // 标签颜色
private int tagMargin; // 标签与头像的水平间距
// 布局常量dp
private static final int DEFAULT_AVATAR_SIZE = 60; // 默认头像大小
private static final int DEFAULT_DRESS_SIZE = 70; // 默认装饰图大小
private static final float DEFAULT_NAME_TEXT_SIZE = 12; // 默认名字字体大小
private static final int DEFAULT_NAME_TEXT_COLOR = 0xFFFFFFFF; // 默认名字颜色
private static final float DEFAULT_TAG_TEXT_SIZE = 12; // 默认标签字体大小
private static final int DEFAULT_TAG_TEXT_COLOR = 0xFFFFE554; // 默认标签颜色
private static final int DEFAULT_TAG_MARGIN = 0; // 默认标签间距
private static final int NAME_MARGIN_TOP = 3; // 名字与标签间距
public QXMeetUserView(Context context) {
super(context);
initAttrs(null);
initSubviews(context);
}
public QXMeetUserView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initAttrs(attrs);
initSubviews(context);
}
public QXMeetUserView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(attrs);
initSubviews(context);
}
// 初始化自定义属性
private void initAttrs(AttributeSet attrs) {
if (attrs == null) {
// 设置默认值
avatarSize = dpToPx(DEFAULT_AVATAR_SIZE);
dressSize = dpToPx(DEFAULT_DRESS_SIZE);
nameTextSize = DEFAULT_NAME_TEXT_SIZE;
nameTextColor = DEFAULT_NAME_TEXT_COLOR;
tagTextSize = DEFAULT_TAG_TEXT_SIZE;
tagTextColor = DEFAULT_TAG_TEXT_COLOR;
tagMargin = dpToPx(DEFAULT_TAG_MARGIN);
return;
}
// 从XML获取属性
TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.QXMeetUserView);
avatarSize = ta.getDimensionPixelSize(R.styleable.QXMeetUserView_avatarSize, dpToPx(DEFAULT_AVATAR_SIZE));
dressSize = ta.getDimensionPixelSize(R.styleable.QXMeetUserView_dressSize, dpToPx(DEFAULT_DRESS_SIZE));
nameTextSize = ta.getDimension(R.styleable.QXMeetUserView_nameTextSize, DEFAULT_NAME_TEXT_SIZE);
nameTextColor = ta.getColor(R.styleable.QXMeetUserView_nameTextColor, DEFAULT_NAME_TEXT_COLOR);
tagTextSize = ta.getDimension(R.styleable.QXMeetUserView_tagTextSize, DEFAULT_TAG_TEXT_SIZE);
tagTextColor = ta.getColor(R.styleable.QXMeetUserView_tagTextColor, DEFAULT_TAG_TEXT_COLOR);
tagMargin = ta.getDimensionPixelSize(R.styleable.QXMeetUserView_tagMargin, dpToPx(DEFAULT_TAG_MARGIN));
ta.recycle();
// 日志输出属性值,便于调试
Log.d(TAG, "属性初始化 - 头像大小: " + avatarSize + ", 装饰大小: " + dressSize);
}
private void initSubviews(Context context) {
setClipChildren(false);
setClipToPadding(false);
setWillNotDraw(false);
// 为整个视图添加背景色,便于调试视图范围
// setBackgroundColor(0x0A000000); // 极浅灰色背景
// 2. 头像(中间层)
headerImageView = new GifAvatarOvalView(context);
headerImageView.setId(View.generateViewId());
headerImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
// 设置强制背景色,确保即使资源加载失败也能看到
// headerImageView.setBackgroundColor(0x33FF0000); // 半透明红色
// 尝试加载默认头像资源
try {
int resId = R.mipmap.default_avatar;
// headerImageView.setImageResource(resId);
Log.d(TAG, "尝试加载默认头像资源: " + resId);
} catch (Exception e) {
Log.e(TAG, "默认头像资源加载失败: " + e.getMessage());
}
LayoutParams headerParams = new LayoutParams(avatarSize, avatarSize);
headerParams.addRule(CENTER_IN_PARENT); // 头像在父容器居中
addView(headerImageView, headerParams);
Log.d(TAG, "头像已添加到视图,大小: " + avatarSize + "x" + avatarSize);
// 1. 装饰图(底层)- 优先初始化确保在最底层
dressImageView = new ImageView(context);
dressImageView.setId(View.generateViewId());
dressImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
// 设置强制背景色,确保即使资源加载失败也能看到
/// dressImageView.setBackgroundColor(0x330000FF); // 半透明蓝色
// 尝试加载装饰图资源
try {
int resId = R.mipmap.xlh_image;
dressImageView.setImageResource(resId);
Log.d(TAG, "尝试加载装饰图资源: " + resId);
} catch (Exception e) {
Log.e(TAG, "装饰图资源加载失败: " + e.getMessage());
}
LayoutParams dressParams = new LayoutParams(dressSize, dressSize);
dressParams.addRule(CENTER_HORIZONTAL);
dressParams.topMargin = dpToPx(5); // 稍微向下移动一点,确保可见
addView(dressImageView, dressParams);
Log.d(TAG, "装饰图已添加到视图,大小: " + dressSize + "x" + dressSize);
// 3. 标签(顶层,与头像底部平齐)
tagLabel = new TextView(context);
tagLabel.setId(View.generateViewId());
tagLabel.setTextColor(tagTextColor);
tagLabel.setTextSize(tagTextSize);
tagLabel.setGravity(Gravity.CENTER);
tagLabel.setText("房主");
tagLabel.setBackground(getRoundedRectBackground(0xFF8D6F28, dpToPx(8)));
tagLabel.setPadding(dpToPx(6), 0, dpToPx(6), 0);
LayoutParams tagParams = new LayoutParams(LayoutParams.WRAP_CONTENT, dpToPx(16));
tagParams.addRule(CENTER_HORIZONTAL);
addView(tagLabel, tagParams);
// 4. 名字(顶层,在标签下方)
nameLabel = new TextView(context);
nameLabel.setId(View.generateViewId());
nameLabel.setTextColor(nameTextColor);
nameLabel.setTextSize(nameTextSize);
nameLabel.setText("虚位以待");
nameLabel.setGravity(Gravity.CENTER);
nameLabel.setSingleLine(true);
LayoutParams nameParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
nameParams.addRule(CENTER_HORIZONTAL);
nameParams.addRule(BELOW, tagLabel.getId());
nameParams.topMargin = dpToPx(NAME_MARGIN_TOP);
addView(nameLabel, nameParams);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 强制设置最小宽高,确保视图可见
int minWidth = Math.max(avatarSize, dressSize);
int minHeight = dressSize + dpToPx(40); // 装饰图高度 + 标签和名字的高度
int width = resolveSizeAndState(minWidth, widthMeasureSpec, 0);
int height = resolveSizeAndState(minHeight, heightMeasureSpec, 0);
setMeasuredDimension(width, height);
// 测量子视图
measureChildren(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
);
Log.d(TAG, "onMeasure - 视图大小: " + width + "x" + height);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
// 确保装饰图正确布局
if (dressImageView != null) {
int dressLeft = (getWidth() - dressSize) / 2;
int dressTop = dpToPx(5); // 顶部留出一点空间
dressImageView.layout(
dressLeft,
dressTop,
dressLeft + dressSize,
dressTop + dressSize
);
Log.d(TAG, "装饰图布局位置: " + dressLeft + "," + dressTop + "," +
(dressLeft + dressSize) + "," + (dressTop + dressSize));
}
// 确保头像正确布局
if (headerImageView != null) {
int avatarLeft = (getWidth() - avatarSize) / 2;
int avatarTop = (dressSize - avatarSize) / 2 + dpToPx(5); // 居中显示在装饰图上
headerImageView.layout(
avatarLeft,
avatarTop,
avatarLeft + avatarSize,
avatarTop + avatarSize
);
Log.d(TAG, "头像布局位置: " + avatarLeft + "," + avatarTop + "," +
(avatarLeft + avatarSize) + "," + (avatarTop + avatarSize));
}
// 标签布局(与头像底部平齐)
if (headerImageView != null && tagLabel != null) {
int avatarBottom = headerImageView.getBottom();
int tagTop = avatarBottom + tagMargin;
int tagLeft = (getWidth() - tagLabel.getMeasuredWidth()) / 2;
tagLabel.layout(
tagLeft,
tagTop,
tagLeft + tagLabel.getMeasuredWidth(),
tagTop + tagLabel.getMeasuredHeight()
);
}
// 名字布局(在标签下方)
if (tagLabel != null && nameLabel != null) {
int tagBottom = tagLabel.getBottom();
int nameTop = tagBottom + dpToPx(NAME_MARGIN_TOP);
int nameLeft = (getWidth() - nameLabel.getMeasuredWidth()) / 2;
nameLabel.layout(
nameLeft,
nameTop,
nameLeft + nameLabel.getMeasuredWidth(),
nameTop + nameLabel.getMeasuredHeight()
);
}
}
// 以下方法保持不变
public void setIsLuckUser(boolean isLuckUser) {
if (tagLabel == null) return;
if (isLuckUser) {
tagLabel.setTextColor(0xFFFFFFFF);
tagLabel.setBackground(getRoundedRectBackground(0xFF6C49E4, dpToPx(8)));
tagLabel.setText("幸运者");
} else {
tagLabel.setTextColor(tagTextColor);
tagLabel.setBackground(getRoundedRectBackground(0xFF8D6F28, dpToPx(8)));
tagLabel.setText("房主");
}
}
public void setModel(BlindBoxBean.xlhUser model) {
if (headerImageView == null || nameLabel == null) return;
if (model != null) {
try {
if (model.getAvatar().toString()!=""){
ImageUtils.loadHeadCC(model.getAvatar(), headerImageView);
}else {
int resId = R.mipmap.default_avatar;
headerImageView.setImageResource(resId);
}
Log.d(TAG, "加载用户头像: " + model.getAvatar());
} catch (Exception e) {
int resId = R.mipmap.default_avatar;
headerImageView.setImageResource(resId);
Log.e(TAG, "加载用户头像失败: " + e.getMessage());
//headerImageView.setBackgroundColor(0x33FF0000); // 保持红色背景以便识别
}
nameLabel.setText(model.getNickname() != null ? model.getNickname() : "虚位以待");
} else {
resetView();
}
}
public void resetView() {
if (headerImageView != null) {
try {
headerImageView.setImageResource(R.mipmap.default_avatar);
} catch (Exception e) {
Log.e(TAG, "重置头像失败: " + e.getMessage());
// headerImageView.setBackgroundColor(0x33FF0000);
}
}
if (nameLabel != null) {
nameLabel.setText("虚位以待");
}
setIsLuckUser(false);
}
private GradientDrawable getRoundedRectBackground(int color, float radius) {
GradientDrawable drawable = new GradientDrawable();
drawable.setColor(color);
drawable.setCornerRadius(radius);
return drawable;
}
private int dpToPx(int dp) {
float density = getResources().getDisplayMetrics().density;
return Math.round(dp * density);
}
// Getter方法
public ImageView getHeaderImageView() { return headerImageView; }
public ImageView getDressImageView() { return dressImageView; }
public TextView getTagLabel() { return tagLabel; }
public TextView getNameLabel() { return nameLabel; }
}

View File

@@ -0,0 +1,860 @@
package com.xscm.moduleutil.view;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Color;
import android.text.InputType;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.xscm.moduleutil.R;
public class QXRedBagSendView extends FrameLayout {
// Properties
private String redBagType = "1";
private String redBagContentType = "1";
private String redBagTime = "0";
private int currentPage = 0;
private boolean isFromRule = false;
// UI Components
private LinearLayout mainContainer;
private ImageView bgImageView;
private TextView titleLabel;
private Button helpBtn;
private Button backBtn;
private Button closeBtn;
private Button nextBtn;
private Button commitBtn;
private LinearLayout firstContentView;
private Button normalRedBagBtn;
private Button pwdRedBagBtn;
private LinearLayout firstPwdView;
private EditText pwdTextField;
private LinearLayout firstTimeView;
private View scrollBgView;
private Button coinRedBagBtn;
private Button diamondRedBagBtn;
private Button selectedRedBagTimeBtn;
private LinearLayout nextContentView;
private TextView moneyLabel;
private TextView moneyUnitLabel;
private EditText moneyTextField;
private EditText countTextField;
private EditText remarkTextField;
private Button noDrawAuthBtn;
private Button collectDrawAuthBtn;
private Button upSeatDrawAuthBtn;
private LinearLayout ruleContentView;
private WebView webView;
private final int[] timeArray = {0, 1, 2, 5, 10};
private final int[] drawAuthArray = {0, 1, 2};
public QXRedBagSendView(Context context) {
super(context);
init(context);
}
public QXRedBagSendView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public QXRedBagSendView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
));
setBackgroundColor(Color.parseColor("#80000000"));
initMainContainer(context);
initTitleBar(context);
initContentArea(context);
initButtons(context);
// 默认选择普通红包
selectedRedBagTypeAction(normalRedBagBtn);
}
private void initMainContainer(Context context) {
mainContainer = new LinearLayout(context);
mainContainer.setOrientation(LinearLayout.VERTICAL);
LayoutParams containerParams = new LayoutParams(
dpToPx(345),
dpToPx(454)
);
containerParams.gravity = Gravity.CENTER;
mainContainer.setLayoutParams(containerParams);
// 背景图片
bgImageView = new ImageView(context);
bgImageView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
));
// 设置背景资源需要你在res/drawable中添加对应的图片
bgImageView.setBackgroundResource(R.mipmap.red_en);
// bgImageView.setBackgroundColor(Color.parseColor("#FFD700")); // 临时颜色
// 将背景图片添加到主容器
mainContainer.addView(bgImageView);
addView(mainContainer);
}
private void initTitleBar(Context context) {
// 标题栏容器
LinearLayout titleContainer = new LinearLayout(context);
titleContainer.setOrientation(LinearLayout.HORIZONTAL);
titleContainer.setGravity(Gravity.CENTER_VERTICAL);
LinearLayout.LayoutParams titleContainerParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
titleContainerParams.setMargins(0, dpToPx(15), 0, 0);
titleContainer.setLayoutParams(titleContainerParams);
// 帮助按钮
helpBtn = createIconButton(context);
helpBtn.setBackgroundColor(Color.TRANSPARENT);
helpBtn.setOnClickListener(v -> helpAction());
titleContainer.addView(helpBtn);
// 返回按钮
backBtn = createIconButton(context);
backBtn.setBackgroundColor(Color.TRANSPARENT);
backBtn.setOnClickListener(v -> backAction());
backBtn.setVisibility(View.GONE);
titleContainer.addView(backBtn);
// 标题
titleLabel = new TextView(context);
titleLabel.setText("直播间红包");
titleLabel.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
titleLabel.setTextColor(Color.WHITE);
titleLabel.setTypeface(titleLabel.getTypeface(), android.graphics.Typeface.BOLD);
LinearLayout.LayoutParams titleParams = new LinearLayout.LayoutParams(
0, ViewGroup.LayoutParams.WRAP_CONTENT, 1
);
titleLabel.setLayoutParams(titleParams);
titleLabel.setGravity(Gravity.CENTER);
titleContainer.addView(titleLabel);
// 关闭按钮
closeBtn = createIconButton(context);
closeBtn.setBackgroundColor(Color.TRANSPARENT);
closeBtn.setOnClickListener(v -> closeAction());
titleContainer.addView(closeBtn);
// 将标题栏添加到主容器(在背景图片之上)
mainContainer.addView(titleContainer);
}
private void initContentArea(Context context) {
// 内容区域容器
LinearLayout contentArea = new LinearLayout(context);
contentArea.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams contentParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
0, 1
);
contentParams.setMargins(dpToPx(15), dpToPx(15), dpToPx(15), dpToPx(15));
contentArea.setLayoutParams(contentParams);
initFirstContentView(context, contentArea);
initNextContentView(context, contentArea);
initRuleView(context, contentArea);
mainContainer.addView(contentArea);
}
private void initButtons(Context context) {
// 按钮容器
LinearLayout buttonContainer = new LinearLayout(context);
buttonContainer.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams buttonParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
buttonParams.setMargins(dpToPx(15), 0, dpToPx(15), dpToPx(15));
buttonContainer.setLayoutParams(buttonParams);
// 下一步按钮
nextBtn = createActionButton(context, "下一步");
nextBtn.setOnClickListener(v -> nextAction());
buttonContainer.addView(nextBtn);
// 提交按钮
commitBtn = createActionButton(context, "发红包");
commitBtn.setOnClickListener(v -> commitAction());
commitBtn.setVisibility(View.GONE);
buttonContainer.addView(commitBtn);
mainContainer.addView(buttonContainer);
}
private void initFirstContentView(Context context, ViewGroup parent) {
firstContentView = new LinearLayout(context);
firstContentView.setOrientation(LinearLayout.VERTICAL);
firstContentView.setLayoutParams(new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
));
parent.addView(firstContentView);
// 顶部视图 - 参与领取限制
LinearLayout firstTopView = createCardView(context);
firstTopView.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams topParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
dpToPx(88)
);
topParams.bottomMargin = dpToPx(12);
firstTopView.setLayoutParams(topParams);
firstContentView.addView(firstTopView);
TextView topTitleLabel = createTitleLabel(context, "参与领取限制");
firstTopView.addView(topTitleLabel);
LinearLayout typeButtonContainer = new LinearLayout(context);
typeButtonContainer.setLayoutParams(new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
));
typeButtonContainer.setWeightSum(2);
firstTopView.addView(typeButtonContainer);
normalRedBagBtn = createTypeButton(context, "普通红包");
normalRedBagBtn.setOnClickListener(v -> selectedRedBagTypeAction(normalRedBagBtn));
typeButtonContainer.addView(normalRedBagBtn);
pwdRedBagBtn = createTypeButton(context, "口令红包");
pwdRedBagBtn.setOnClickListener(v -> selectedRedBagTypeAction(pwdRedBagBtn));
typeButtonContainer.addView(pwdRedBagBtn);
// 口令输入视图
firstPwdView = createInputCard(context, "口令", "请输入口令");
pwdTextField = (EditText) ((LinearLayout) firstPwdView).getChildAt(1);
firstContentView.addView(firstPwdView);
// 时间选择视图
firstTimeView = createCardView(context);
firstTimeView.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams timeParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
dpToPx(88)
);
timeParams.bottomMargin = dpToPx(12);
firstTimeView.setLayoutParams(timeParams);
firstContentView.addView(firstTimeView);
TextView timeTitleLabel = createTitleLabel(context, "开奖倒计时");
firstTimeView.addView(timeTitleLabel);
LinearLayout timeButtonContainer = new LinearLayout(context);
timeButtonContainer.setLayoutParams(new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
));
firstTimeView.addView(timeButtonContainer);
// 创建时间选择按钮
for (int time : timeArray) {
Button timeBtn = createTimeButton(context, time);
timeBtn.setOnClickListener(v -> redBagTimeAction(timeBtn));
if (time == 0) {
timeBtn.setSelected(true);
selectedRedBagTimeBtn = timeBtn;
}
timeButtonContainer.addView(timeBtn);
}
// 红包类型选择
LinearLayout bottomView = createCardView(context);
bottomView.setOrientation(LinearLayout.HORIZONTAL);
bottomView.setGravity(Gravity.CENTER_VERTICAL);
LinearLayout.LayoutParams bottomParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
dpToPx(48)
);
bottomView.setLayoutParams(bottomParams);
firstContentView.addView(bottomView);
TextView redBagTypeLabel = createTitleLabel(context, "红包类型");
bottomView.addView(redBagTypeLabel);
// 红包类型切换容器
RelativeLayout typeSwitchContainer = new RelativeLayout(context);
LinearLayout.LayoutParams switchParams = new LinearLayout.LayoutParams(
dpToPx(130),
dpToPx(26)
);
switchParams.gravity = Gravity.CENTER_VERTICAL;
typeSwitchContainer.setLayoutParams(switchParams);
typeSwitchContainer.setBackgroundColor(Color.parseColor("#BA230A"));
typeSwitchContainer.setPadding(dpToPx(2), dpToPx(2), dpToPx(2), dpToPx(2));
bottomView.addView(typeSwitchContainer);
scrollBgView = new View(context);
RelativeLayout.LayoutParams scrollParams = new RelativeLayout.LayoutParams(
dpToPx(63),
ViewGroup.LayoutParams.MATCH_PARENT
);
scrollBgView.setLayoutParams(scrollParams);
scrollBgView.setBackgroundColor(Color.parseColor("#FDE8A3"));
typeSwitchContainer.addView(scrollBgView);
coinRedBagBtn = createContentTypeButton(context, "金币红包");
coinRedBagBtn.setSelected(true);
coinRedBagBtn.setOnClickListener(v -> redBagContentTypeAction(coinRedBagBtn));
typeSwitchContainer.addView(coinRedBagBtn);
diamondRedBagBtn = createContentTypeButton(context, "钻石红包");
diamondRedBagBtn.setOnClickListener(v -> redBagContentTypeAction(diamondRedBagBtn));
typeSwitchContainer.addView(diamondRedBagBtn);
}
private void initNextContentView(Context context, ViewGroup parent) {
nextContentView = new LinearLayout(context);
nextContentView.setOrientation(LinearLayout.VERTICAL);
nextContentView.setLayoutParams(new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
));
nextContentView.setVisibility(View.GONE);
parent.addView(nextContentView);
// 可用余额标签
moneyLabel = new TextView(context);
moneyLabel.setText("-金币可用");
moneyLabel.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13);
moneyLabel.setTextColor(Color.WHITE);
LinearLayout.LayoutParams moneyLabelParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
moneyLabelParams.gravity = Gravity.END;
moneyLabel.setLayoutParams(moneyLabelParams);
nextContentView.addView(moneyLabel);
// 金额输入
LinearLayout moneyBgView = createInputCard(context, "金额", "请输入红包金额");
moneyTextField = (EditText) moneyBgView.getChildAt(1);
moneyUnitLabel = new TextView(context);
moneyUnitLabel.setText("金币");
moneyUnitLabel.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13);
moneyUnitLabel.setTextColor(Color.parseColor("#666666"));
LinearLayout.LayoutParams unitParams = new LinearLayout.LayoutParams(
dpToPx(30),
ViewGroup.LayoutParams.WRAP_CONTENT
);
moneyUnitLabel.setLayoutParams(unitParams);
moneyBgView.addView(moneyUnitLabel);
nextContentView.addView(moneyBgView);
// 个数输入
LinearLayout countBgView = createInputCard(context, "个数", "请输入红包数量");
countTextField = (EditText) countBgView.getChildAt(1);
TextView countUnitLabel = new TextView(context);
countUnitLabel.setText("");
countUnitLabel.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13);
countUnitLabel.setTextColor(Color.parseColor("#666666"));
countUnitLabel.setLayoutParams(unitParams);
countBgView.addView(countUnitLabel);
nextContentView.addView(countBgView);
// 领取条件
LinearLayout drawAuthBgView = createCardView(context);
drawAuthBgView.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams authParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
dpToPx(88)
);
authParams.bottomMargin = dpToPx(12);
drawAuthBgView.setLayoutParams(authParams);
nextContentView.addView(drawAuthBgView);
TextView authTitleLabel = createTitleLabel(context, "条件");
drawAuthBgView.addView(authTitleLabel);
LinearLayout authButtonContainer = new LinearLayout(context);
authButtonContainer.setLayoutParams(new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
));
drawAuthBgView.addView(authButtonContainer);
// 创建领取条件按钮
noDrawAuthBtn = createAuthButton(context, "");
noDrawAuthBtn.setSelected(true);
noDrawAuthBtn.setOnClickListener(v -> drawAuthAction(noDrawAuthBtn));
authButtonContainer.addView(noDrawAuthBtn);
collectDrawAuthBtn = createAuthButton(context, "收藏房间");
collectDrawAuthBtn.setOnClickListener(v -> drawAuthAction(collectDrawAuthBtn));
authButtonContainer.addView(collectDrawAuthBtn);
upSeatDrawAuthBtn = createAuthButton(context, "仅麦上用户");
upSeatDrawAuthBtn.setOnClickListener(v -> drawAuthAction(upSeatDrawAuthBtn));
authButtonContainer.addView(upSeatDrawAuthBtn);
// 备注输入
LinearLayout remarkBgView = createInputCard(context, "备注", "请输入备注");
remarkTextField = (EditText) remarkBgView.getChildAt(1);
nextContentView.addView(remarkBgView);
}
private void initRuleView(Context context, ViewGroup parent) {
ruleContentView = new LinearLayout(context);
ruleContentView.setOrientation(LinearLayout.VERTICAL);
ruleContentView.setLayoutParams(new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
));
ruleContentView.setBackgroundColor(Color.WHITE);
ruleContentView.setPadding(dpToPx(15), dpToPx(15), dpToPx(15), dpToPx(15));
ruleContentView.setVisibility(View.GONE);
parent.addView(ruleContentView);
webView = new WebView(context);
webView.setLayoutParams(new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
));
ruleContentView.addView(webView);
}
// 工具方法
private Button createIconButton(Context context) {
Button button = new Button(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
dpToPx(40),
dpToPx(40)
);
button.setLayoutParams(params);
return button;
}
private Button createActionButton(Context context, String text) {
Button button = new Button(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
dpToPx(44)
);
button.setLayoutParams(params);
button.setText(text);
button.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
button.setTextColor(Color.parseColor("#F35248"));
button.setTypeface(button.getTypeface(), android.graphics.Typeface.BOLD);
button.setBackgroundColor(Color.parseColor("#FDE8A3")); // 临时背景色
return button;
}
private LinearLayout createCardView(Context context) {
LinearLayout card = new LinearLayout(context);
card.setBackgroundColor(Color.WHITE);
card.setPadding(dpToPx(15), dpToPx(11), dpToPx(15), dpToPx(5));
return card;
}
private TextView createTitleLabel(Context context, String text) {
TextView label = new TextView(context);
label.setText(text);
label.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
label.setTextColor(Color.parseColor("#666666"));
label.setTypeface(label.getTypeface(), android.graphics.Typeface.BOLD);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
dpToPx(26)
);
label.setLayoutParams(params);
return label;
}
private Button createTypeButton(Context context, String text) {
Button button = new Button(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
0, dpToPx(36), 1
);
params.setMargins(0, 0, dpToPx(10), 0);
button.setLayoutParams(params);
button.setText(text);
button.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15);
button.setTextColor(Color.WHITE);
button.setTypeface(button.getTypeface(), android.graphics.Typeface.BOLD);
button.setBackgroundColor(Color.parseColor("#FF9999")); // 临时背景色
return button;
}
private LinearLayout createInputCard(Context context, String title, String hint) {
LinearLayout card = new LinearLayout(context);
card.setOrientation(LinearLayout.HORIZONTAL);
card.setGravity(Gravity.CENTER_VERTICAL);
LinearLayout.LayoutParams cardParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
dpToPx(48)
);
cardParams.bottomMargin = dpToPx(12);
card.setLayoutParams(cardParams);
card.setBackgroundColor(Color.WHITE);
card.setPadding(dpToPx(15), 0, dpToPx(15), 0);
TextView titleLabel = createTitleLabel(context, title);
card.addView(titleLabel);
EditText editText = new EditText(context);
LinearLayout.LayoutParams editParams = new LinearLayout.LayoutParams(
0, ViewGroup.LayoutParams.MATCH_PARENT, 1
);
editParams.setMargins(dpToPx(15), 0, dpToPx(15), 0);
editText.setLayoutParams(editParams);
editText.setHint(hint);
editText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
editText.setTextColor(Color.parseColor("#666666"));
editText.setGravity(Gravity.END);
editText.setBackground(null);
editText.setInputType(InputType.TYPE_CLASS_TEXT);
card.addView(editText);
return card;
}
private Button createTimeButton(Context context, int minutes) {
Button button = new Button(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
dpToPx(49), dpToPx(36)
);
params.setMargins(0, 0, dpToPx(10), 0);
button.setLayoutParams(params);
String text = minutes == 0 ? "立刻" : minutes + "分钟";
button.setText(text);
button.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
button.setTypeface(button.getTypeface(), android.graphics.Typeface.BOLD);
button.setBackgroundColor(Color.parseColor("#EEEEEE")); // 临时背景色
return button;
}
private Button createContentTypeButton(Context context, String text) {
Button button = new Button(context);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
dpToPx(63), ViewGroup.LayoutParams.MATCH_PARENT
);
button.setLayoutParams(params);
button.setText(text);
button.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
button.setBackgroundColor(Color.TRANSPARENT);
button.setTextColor(Color.parseColor("#FFC9C7"));
return button;
}
private Button createAuthButton(Context context, String text) {
Button button = new Button(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
0, dpToPx(36), 1
);
params.setMargins(0, 0, dpToPx(10), 0);
button.setLayoutParams(params);
button.setText(text);
button.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
button.setTypeface(button.getTypeface(), android.graphics.Typeface.BOLD);
button.setBackgroundColor(Color.parseColor("#EEEEEE")); // 临时背景色
return button;
}
private int dpToPx(int dp) {
return (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dp,
getResources().getDisplayMetrics()
);
}
// Action Methods
private void nextAction() {
currentPage = 1;
moneyUnitLabel.setText(redBagContentType.equals("1") ? "金币" : "钻石");
backBtn.setVisibility(View.GONE);
helpBtn.setVisibility(View.VISIBLE);
nextBtn.setVisibility(View.GONE);
commitBtn.setVisibility(View.VISIBLE);
switchContentView(firstContentView, nextContentView);
}
private void commitAction() {
// 实现发红包逻辑
}
private void helpAction() {
isFromRule = true;
webView.loadUrl("http://www.baidu.com");
backBtn.setVisibility(View.VISIBLE);
helpBtn.setVisibility(View.GONE);
nextBtn.setVisibility(View.GONE);
commitBtn.setVisibility(View.GONE);
View currentView = currentPage == 1 ? nextContentView : firstContentView;
switchContentView(currentView, ruleContentView);
}
private void closeAction() {
hide();
}
private void backAction() {
backBtn.setVisibility(View.GONE);
helpBtn.setVisibility(View.VISIBLE);
View currentView = currentPage == 1 ? nextContentView : firstContentView;
nextBtn.setVisibility(currentPage == 0 ? View.VISIBLE : View.GONE);
commitBtn.setVisibility(currentPage == 1 ? View.VISIBLE : View.GONE);
switchContentView(ruleContentView, currentView);
isFromRule = false;
}
private void selectedRedBagTypeAction(Button sender) {
if (sender.isSelected()) return;
if (sender == normalRedBagBtn) {
pwdRedBagBtn.setSelected(false);
normalRedBagBtn.setSelected(true);
firstPwdView.setVisibility(View.GONE);
// 调整时间视图位置
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) firstTimeView.getLayoutParams();
params.topMargin = 0;
params.bottomMargin = dpToPx(12);
firstTimeView.setLayoutParams(params);
redBagType = "1";
} else {
pwdRedBagBtn.setSelected(true);
normalRedBagBtn.setSelected(false);
firstPwdView.setVisibility(View.VISIBLE);
// 调整时间视图位置
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) firstTimeView.getLayoutParams();
params.topMargin = dpToPx(60);
params.bottomMargin = dpToPx(12);
firstTimeView.setLayoutParams(params);
redBagType = "2";
}
// 更新按钮背景色
updateButtonSelection(normalRedBagBtn, sender == normalRedBagBtn);
updateButtonSelection(pwdRedBagBtn, sender == pwdRedBagBtn);
}
private void redBagContentTypeAction(Button sender) {
if (sender.isSelected()) return;
if (sender == coinRedBagBtn) {
diamondRedBagBtn.setSelected(false);
coinRedBagBtn.setSelected(true);
redBagContentType = "1";
animateSwitchBg(true);
} else {
coinRedBagBtn.setSelected(false);
diamondRedBagBtn.setSelected(true);
redBagContentType = "2";
animateSwitchBg(false);
}
// 更新按钮文字颜色
updateContentTypeButtonColor(coinRedBagBtn, coinRedBagBtn.isSelected());
updateContentTypeButtonColor(diamondRedBagBtn, diamondRedBagBtn.isSelected());
}
private void drawAuthAction(Button sender) {
if (sender == noDrawAuthBtn) {
noDrawAuthBtn.setSelected(true);
collectDrawAuthBtn.setSelected(false);
upSeatDrawAuthBtn.setSelected(false);
} else if (sender == collectDrawAuthBtn) {
collectDrawAuthBtn.setSelected(!collectDrawAuthBtn.isSelected());
if (upSeatDrawAuthBtn.isSelected() || collectDrawAuthBtn.isSelected()) {
noDrawAuthBtn.setSelected(false);
} else {
noDrawAuthBtn.setSelected(true);
}
} else if (sender == upSeatDrawAuthBtn) {
noDrawAuthBtn.setSelected(false);
upSeatDrawAuthBtn.setSelected(!upSeatDrawAuthBtn.isSelected());
if (upSeatDrawAuthBtn.isSelected() || collectDrawAuthBtn.isSelected()) {
noDrawAuthBtn.setSelected(false);
} else {
noDrawAuthBtn.setSelected(true);
}
}
// 更新按钮背景色
updateAuthButtonSelection(noDrawAuthBtn, noDrawAuthBtn.isSelected());
updateAuthButtonSelection(collectDrawAuthBtn, collectDrawAuthBtn.isSelected());
updateAuthButtonSelection(upSeatDrawAuthBtn, upSeatDrawAuthBtn.isSelected());
}
private void redBagTimeAction(Button sender) {
if (sender.isSelected()) return;
if (selectedRedBagTimeBtn != null) {
selectedRedBagTimeBtn.setSelected(false);
updateTimeButtonSelection(selectedRedBagTimeBtn, false);
}
sender.setSelected(true);
selectedRedBagTimeBtn = sender;
int minutes = 0;
try {
String text = sender.getText().toString();
if (text.equals("立刻")) {
minutes = 0;
} else {
minutes = Integer.parseInt(text.replace("分钟", ""));
}
} catch (Exception e) {
minutes = 0;
}
redBagTime = String.valueOf(minutes * 60);
updateTimeButtonSelection(sender, true);
}
// Helper Methods
private void switchContentView(View hideView, View showView) {
hideView.setVisibility(View.GONE);
showView.setVisibility(View.VISIBLE);
}
private void updateButtonSelection(Button button, boolean selected) {
button.setBackgroundColor(selected ?
Color.parseColor("#FF5555") : Color.parseColor("#FF9999"));
}
private void updateTimeButtonSelection(Button button, boolean selected) {
button.setBackgroundColor(selected ?
Color.parseColor("#FF5555") : Color.parseColor("#EEEEEE"));
}
private void updateAuthButtonSelection(Button button, boolean selected) {
button.setBackgroundColor(selected ?
Color.parseColor("#FF5555") : Color.parseColor("#EEEEEE"));
}
private void updateContentTypeButtonColor(Button button, boolean selected) {
button.setTextColor(selected ?
Color.parseColor("#D01717") : Color.parseColor("#FFC9C7"));
}
private void animateSwitchBg(boolean toLeft) {
int targetX = toLeft ? 0 : dpToPx(63);
ValueAnimator animator = ValueAnimator.ofInt(
((RelativeLayout.LayoutParams) scrollBgView.getLayoutParams()).leftMargin,
targetX
);
animator.addUpdateListener(animation -> {
int value = (int) animation.getAnimatedValue();
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) scrollBgView.getLayoutParams();
params.leftMargin = value;
scrollBgView.setLayoutParams(params);
});
animator.setDuration(300);
animator.setInterpolator(new DecelerateInterpolator());
animator.start();
}
// Public Methods
public void showInView(ViewGroup parent) {
parent.addView(this);
// 添加入场动画
mainContainer.setTranslationY(-getHeight());
mainContainer.animate()
.translationY(0)
.setDuration(300)
.setInterpolator(new DecelerateInterpolator())
.start();
}
public void hide() {
// 添加退场动画
mainContainer.animate()
.translationY(getHeight())
.setDuration(300)
.setInterpolator(new DecelerateInterpolator())
.withEndAction(() -> {
ViewGroup parent = (ViewGroup) getParent();
if (parent != null) {
parent.removeView(QXRedBagSendView.this);
}
})
.start();
}
// Getter methods
public String getRedBagType() {
return redBagType;
}
public String getRedBagContentType() {
return redBagContentType;
}
public String getRedBagTime() {
return redBagTime;
}
public String getPassword() {
return pwdTextField.getText().toString();
}
public String getMoney() {
return moneyTextField.getText().toString();
}
public String getCount() {
return countTextField.getText().toString();
}
public String getRemark() {
return remarkTextField.getText().toString();
}
public int getDrawAuth() {
if (noDrawAuthBtn.isSelected()) return 0;
if (collectDrawAuthBtn.isSelected()) return 1;
if (upSeatDrawAuthBtn.isSelected()) return 2;
return 0;
}
}

View File

@@ -0,0 +1,268 @@
package com.xscm.moduleutil.view;
import android.content.Context;
import android.graphics.Typeface;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.ScaleAnimation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.xscm.moduleutil.R;
public class QXTimeDownView extends FrameLayout {
private ImageView bgImageView;
private TextView titleLabel;
private TextView timeLabel;
private TextView bigTimeLabel;
private long endTime;
private long startTime;
private Handler timerHandler;
private Runnable timerRunnable;
private TimeDownDelegate delegate;
public interface TimeDownDelegate {
void timeDownStartAnimation();
void timeDownUpdateAnimationWithTime(long time);
void timeDownStopAnimation();
void timeDownDidFinished();
}
public QXTimeDownView(Context context) {
super(context);
initSubviews(context);
}
public QXTimeDownView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initSubviews(context);
}
public QXTimeDownView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initSubviews(context);
}
private void initSubviews(Context context) {
// 背景图片(最大的圆圈)
bgImageView = new ImageView(context);
bgImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
bgImageView.setImageResource(R.drawable.ac_time_down_bg);
LayoutParams bgParams = new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT
);
bgParams.gravity = Gravity.CENTER;
addView(bgImageView, bgParams);
// 时间标签(居中显示在背景图上)
timeLabel = new TextView(context);
timeLabel.setTextSize(16);
timeLabel.setTextColor(0xFFFFECA7);
timeLabel.setGravity(Gravity.CENTER);
timeLabel.setTypeface(android.graphics.Typeface.create("sans-serif-condensed", android.graphics.Typeface.NORMAL));
LayoutParams timeParams = new LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
);
timeParams.gravity = Gravity.CENTER;
timeParams.topMargin = dpToPx(-10);
addView(timeLabel, timeParams);
// 标题标签(显示在时间标签下方)
titleLabel = new TextView(context);
titleLabel.setTextSize(12);
titleLabel.setTextColor(0xFFFFECA7);
titleLabel.setText("倒计时");
titleLabel.setGravity(Gravity.CENTER);
LayoutParams titleParams = new LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
);
titleParams.gravity = Gravity.CENTER;
titleParams.topMargin = dpToPx(12); // 在timeLabel下方一定距离
addView(titleLabel, titleParams);
// 大时间标签初始隐藏用于最后30秒显示
bigTimeLabel = new TextView(context);
bigTimeLabel.setTextSize(20);
bigTimeLabel.setText("-");
bigTimeLabel.setTextColor(0xFFFFECA7);
bigTimeLabel.setGravity(Gravity.CENTER);
bigTimeLabel.setVisibility(View.GONE);
bigTimeLabel.setTypeface(Typeface.create("semibold", Typeface.NORMAL));
LayoutParams bigTimeParams = new LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
);
bigTimeParams.gravity = Gravity.CENTER;
addView(bigTimeLabel, bigTimeParams);
// 初始化定时器
timerHandler = new Handler(Looper.getMainLooper());
}
public void setEndTime(long endTime) {
this.endTime = endTime;
// 获取当前时间(秒)
long currentTime = System.currentTimeMillis() / 1000;
this.startTime = endTime - currentTime;
if (this.startTime <= 0) {
// 时间错误不进行倒计时
showBigTimeLabel("0");
return;
}
stopTimer();
startTimer();
}
private void startTimer() {
timerRunnable = new Runnable() {
@Override
public void run() {
startTime--;
long min = (startTime % 3600) / 60;
long second = startTime % 60;
if (startTime <= 30) {
// 最后30秒显示大数字
showBigTimeLabel(String.valueOf(startTime));
if (startTime == 30) {
if (delegate != null) {
delegate.timeDownStartAnimation();
}
} else {
if (delegate != null) {
delegate.timeDownUpdateAnimationWithTime(startTime);
}
}
// 弹性动画
performScaleAnimation();
} else {
// 正常倒计时显示
showNormalTime(String.format("%02d:%02d", min, second));
if (delegate != null) {
delegate.timeDownStopAnimation();
}
}
if (startTime <= 0) {
stopTimer();
showBigTimeLabel("0");
if (delegate != null) {
delegate.timeDownDidFinished();
delegate.timeDownStopAnimation();
}
} else {
// 继续下一次计时
timerHandler.postDelayed(this, 1000);
}
}
};
// 立即开始第一次执行
timerHandler.post(timerRunnable);
}
public void stopTimer() {
if (timerHandler != null && timerRunnable != null) {
timerHandler.removeCallbacks(timerRunnable);
timerRunnable = null;
}
}
private void showBigTimeLabel(String text) {
bigTimeLabel.setVisibility(View.VISIBLE);
timeLabel.setVisibility(View.GONE);
titleLabel.setVisibility(View.GONE);
bigTimeLabel.setText(text);
}
private void showNormalTime(String timeText) {
bigTimeLabel.setVisibility(View.GONE);
timeLabel.setVisibility(View.VISIBLE);
titleLabel.setVisibility(View.VISIBLE);
timeLabel.setText(timeText);
}
private void performScaleAnimation() {
ScaleAnimation scaleAnimation = new ScaleAnimation(
1.0f, 1.5f, // X轴从1.0缩放到1.5
1.0f, 1.5f, // Y轴从1.0缩放到1.5
ScaleAnimation.RELATIVE_TO_SELF, 0.5f, // 缩放中心X
ScaleAnimation.RELATIVE_TO_SELF, 0.5f // 缩放中心Y
);
scaleAnimation.setDuration(600);
scaleAnimation.setFillAfter(false);
bigTimeLabel.startAnimation(scaleAnimation);
}
public void reset() {
stopTimer();
showNormalTime("00:00");
bigTimeLabel.setVisibility(View.GONE);
timeLabel.setVisibility(View.VISIBLE);
titleLabel.setVisibility(View.VISIBLE);
}
// 辅助方法dp 转 px
private int dpToPx(int dp) {
float density = getResources().getDisplayMetrics().density;
return Math.round(dp * density);
}
// Getter 和 Setter 方法
public void setDelegate(TimeDownDelegate delegate) {
this.delegate = delegate;
}
public long getEndTime() {
return endTime;
}
public long getStartTime() {
return startTime;
}
public TextView getTitleLabel() {
return titleLabel;
}
public TextView getTimeLabel() {
return timeLabel;
}
public TextView getBigTimeLabel() {
return bigTimeLabel;
}
public ImageView getBgImageView() {
return bgImageView;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
stopTimer();
}
}

View File

@@ -0,0 +1,207 @@
package com.xscm.moduleutil.view
import android.content.Context
import android.graphics.Color
import android.graphics.Typeface
import android.text.Html
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.TextPaint
import android.text.method.LinkMovementMethod
import android.text.style.*
import android.util.Log
import android.util.AttributeSet
import android.view.View
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.annotation.StringRes
/**
* 封装了富文本展示功能的自定义TextView
* 支持HTML格式、自定义样式文本和点击事件
*/
class RichTextView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : androidx.appcompat.widget.AppCompatTextView(context, attrs, defStyleAttr) {
// 富文本构建器
private val spannableBuilder = SpannableStringBuilder()
init {
// 初始化配置
movementMethod = LinkMovementMethod.getInstance()
highlightColor = Color.TRANSPARENT // 移除点击高亮
}
/**
* 设置HTML格式的富文本
*/
fun setHtmlText(html: String) {
val spanned = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
Html.fromHtml(html, Html.FROM_HTML_MODE_COMPACT)
} else {
@Suppress("DEPRECATION")
Html.fromHtml(html)
}
text = spanned
}
/**
* 从资源文件设置HTML富文本
*/
fun setHtmlText(@StringRes resId: Int) {
setHtmlText(context.getString(resId))
}
/**
* 开始构建富文本
*/
fun beginBuild(): RichTextBuilder {
spannableBuilder.clear()
return RichTextBuilder()
}
/**
* 富文本构建器
* 支持链式调用添加各种样式的文本
*/
inner class RichTextBuilder {
/**
* 添加普通文本
*/
fun addText(text: String): RichTextBuilder {
spannableBuilder.append(text)
return this
}
/**
* 添加普通文本(从资源文件)
*/
fun addText(@StringRes resId: Int): RichTextBuilder {
return addText(context.getString(resId))
}
/**
* 添加加粗文本
*/
fun addBoldText(text: String): RichTextBuilder {
return addStyledText(text, StyleSpan(Typeface.BOLD))
}
/**
* 添加斜体文本
*/
fun addItalicText(text: String): RichTextBuilder {
return addStyledText(text, StyleSpan(Typeface.ITALIC))
}
/**
* 添加下划线文本
*/
fun addUnderlineText(text: String): RichTextBuilder {
return addStyledText(text, UnderlineSpan())
}
/**
* 添加删除线文本
*/
fun addStrikethroughText(text: String): RichTextBuilder {
return addStyledText(text, StrikethroughSpan())
}
/**
* 添加指定颜色的文本
*/
fun addColoredText(text: String, @ColorInt color: Int): RichTextBuilder {
return addStyledText(text, ForegroundColorSpan(color))
}
/**
* 添加指定背景色的文本
*/
fun addBackgroundColoredText(text: String, @ColorInt color: Int): RichTextBuilder {
return addStyledText(text, BackgroundColorSpan(color))
}
/**
* 添加指定大小的文本
* @param proportion 相对于默认大小的比例
*/
fun addSizedText(text: String, proportion: Float): RichTextBuilder {
return addStyledText(text, RelativeSizeSpan(proportion))
}
/**
* 添加带有点击事件的文本
*/
fun addClickableText(
text: String,
@ColorInt linkColor: Int = Color.BLUE,
isUnderline: Boolean = false,
onClick: () -> Unit
): RichTextBuilder {
val start = spannableBuilder.length
spannableBuilder.append(text)
val end = spannableBuilder.length
val clickableSpan = object : ClickableSpan() {
override fun onClick(widget: View) {
onClick.invoke()
}
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.color = linkColor
ds.isUnderlineText = isUnderline
}
}
spannableBuilder.setSpan(
clickableSpan,
start,
end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
return this
}
/**
* 添加换行
*/
fun addLineBreak(): RichTextBuilder {
spannableBuilder.append("\n")
return this
}
/**
* 添加自定义样式的文本
*/
fun addStyledText(text: String, vararg spans: Any): RichTextBuilder {
val start = spannableBuilder.length
spannableBuilder.append(text)
val end = spannableBuilder.length
spans.forEach { span ->
spannableBuilder.setSpan(
span,
start,
end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
return this
}
/**
* 完成构建并应用到TextView
*/
fun build() {
text = spannableBuilder
}
}
}