@@ -1,17 +1,11 @@
package com.xscm.moduleutil.view ;
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.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 ;
@@ -19,232 +13,320 @@ import android.widget.TextView;
import androidx.annotation.Nullable ;
import com.bumptech.glide.Glide ;
import com.xscm.moduleutil.R ;
import com.xscm.moduleutil.bean.UserInfo ;
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 GifAvatarOvalView headerImageView ; // 头像
private ImageView dressImageView ; // 装饰图
private TextView tagLabel ; // 标签
private TextView nameLabel ; // 名称
private boolean isLuckUser ;
private Object model ; // 这里用 Object 代替 QXUserModel
// 布局属性变量
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 . setScaleType ( ImageView . ScaleType . FIT_CENTER ) ; // 添加这一行
// headerImageView. setScaleType( ImageView. ScaleType. FIT_CENTER) ;
// headerImageView.setImageResource(R.mipmap.default_avatar);
headerImageView . setId ( View . generateViewId ( ) ) ;
headerImageView. setScaleType( ImageView. ScaleType. FIT_CENTER) ;
// 设置强制背景色,确保即使资源加载失败也能看到
// headerImageView.setBackgroundColor(0x33FF0000); // 半透明红色
int headerSize = getMeasuredWidth ( ) - dpToPx ( 18 ) ; // self.width-9*2
LayoutParams headerParams = new LayoutParams ( headerSize , headerSize ) ;
headerParams . setMargins ( 0 , 10 , 0 , 0 ) ;
headerParams . addRule ( CENTER_IN_PARENT ) ;
// 将头像添加到装饰视图之上
// 尝试加载默认头像资源
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 . setImageResource ( R . mipmap . xlh_image ) ;
// 设置强制背景色,确保即使资源加载失败也能看到
/// dressImageView.setBackgroundColor(0x330000FF); // 半透明蓝色
LayoutParams dressParams = new LayoutParams (
LayoutParams . MATCH_PARENT ,
LayoutParams . MATCH_PARENT
) ;
// 尝试加载装饰图资源
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 . setTextColor ( 0xFFFFE554 ) ; // RGB16(0xFFE554)
tagLabel . setTextSize ( 12 ) ;
tagLabel . setGravity ( android . view . Gravity . CENTER ) ;
tagLabel . setBackground ( getRoundedRectBackground ( 0xFF8D6F28 , dpToPx ( 8 ) ) ) ; // 默认房主背景色
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 ( dpToPx ( 45 ) , dpToPx ( 16 ) ) ;
LayoutParams tagParams = new LayoutParams ( LayoutParams . WRAP_CONTENT , dpToPx ( 16 ) ) ;
tagParams . addRule ( CENTER_HORIZONTAL ) ;
// 需要在测量完成后设置底部位置
addView ( tagLabel , tagParams ) ;
// 创建名称标签
// 4. 名字(顶层,在标签下方)
nameLabel = new TextView ( context ) ;
nameLabel . setTextColor ( 0xFFFFFFFF ) ; // RGB16(0xffffff)
nameLabel . setTextSize ( 12 ) ;
nameLabel . setId ( View . generateViewId ( ) ) ;
nameLabel . setTextColor ( nameTextColor ) ;
nameLabel . setTextSize ( nameTextSize ) ;
nameLabel . setText ( " 虚位以待 " ) ;
nameLabel . setGravity ( android . view . Gravity. CENTER ) ;
nameLabel . setGravity ( Gravity . CENTER ) ;
nameLabel . setSingleLine ( true ) ;
LayoutParams nameParams = new LayoutParams (
LayoutParams . WRAP_CONTENT ,
LayoutParams . WRAP_CONTENT
) ;
LayoutParams nameParams = new LayoutParams ( LayoutParams . WRAP_CONTENT , LayoutParams . WRAP_CONTENT ) ;
nameParams . addRule ( CENTER_HORIZONTAL ) ;
nameParams . addRule ( ALIGN_PARENT_BOTTOM ) ;
nameParams . addRule ( BELOW , tagLabel . getId ( ) ) ;
nameParams . topMargin = dpToPx ( NAME_MARGIN_TOP ) ;
addView ( nameLabel , nameParams ) ;
}
@Override
protected void onMeasure ( int widthMeasureSpec , int heightMeasureSpec ) {
super . onMeasure ( widthMeasureSpec , heightMeasureSpec ) ;
// 强制设置最小宽高,确保视图可见
int minWidth = Math . max ( avatarSize , dressSize ) ;
int minHeight = dressSize + dpToPx ( 40 ) ; // 装饰图高度 + 标签和名字的高度
// 确保在测量时设置正确的头像尺寸
if ( headerImageView ! = null ) {
int headerSize = getMeasuredWidth ( ) - dpToPx ( 18 ) ; // width - 9dp * 2
LayoutParams headerParams = ( LayoutParams ) headerImageView . getLayoutParams ( ) ;
if ( headerParams ! = null ) {
headerParams . width = headerSize ;
h eaderParams . height = headerSize ;
h eaderParams . leftMargin = dpToPx ( 9 ) ;
h eaderParams . topMargin = dpToPx ( 9 ) ;
headerImageView . setLayoutParams ( headerParams ) ;
}
}
int width = resolveSizeAndState ( minWidth , widthMeasureSpec , 0 ) ;
int height = resolveSizeAndState ( minHeight , heightMeasureSpec , 0 ) ;
setMeasuredDimension ( width , height ) ;
// 测量子视图
m easureChildren (
M easureSpec . makeMeasureSpec ( width , MeasureSpec . EXACTLY ) ,
M easureSpec . 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 ) ;
// 在布局完成后设置标签的位置(在头像底部-8的位置)
if ( changed & & headerImageView ! = null & & tagLabel ! = null ) {
int tagTop = headerImageView . getBottom ( ) - dpToPx ( 8 ) ;
int tagLeft = ( getWidth ( ) - tagLabel . getWidth ( ) ) / 2 ;
tagLabel . layout ( tagLeft , tagTop , tagLeft + tagLabel . getWidth ( ) , tagTop + tagLabel . getHeight ( ) ) ;
// 确保装饰图正确布局
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 ) {
this . isLuckUser = isLuckUser ;
if ( tagLabel = = null ) return ;
if ( isLuckUser ) {
tagLabel . setTextColor ( 0xFFFFFFFF ) ; // RGB16(0xffffff)
tagLabel . setBackground ( getRoundedRectBackground ( 0xFF6C49E4 , dpToPx ( 8 ) ) ) ; // RGB16(0x6C49E4)
// tagLabel.setBackgroundColor(getResources().getColor(R.color.color_FF6C49E4)); // RGB16(0x6C49E4)
tagLabel . setTextColor ( 0xFFFFFFFF ) ;
tagLabel . setBackground ( getRoundedRectBackground ( 0xFF6C49E4 , dpToPx ( 8 ) ) ) ;
tagLabel . setText ( " 幸运者 " ) ;
} else {
tagLabel . setTextColor ( 0xFFFFE554 ) ; // RGB16(0xFFE554)
tagLabel . setBackground ( getRoundedRectBackground ( 0xFF8D6F28 , dpToPx ( 8 ) ) ) ; // RGB16(0x8D6F28)
// tagLabel.setBackgroundColor(getResources().getColor(R.color.color_FF8D6F28)); // RGB16(0x6C49E4)
tagLabel . setTextColor ( tagTextColor ) ;
tagLabel . setBackground ( getRoundedRectBackground ( 0xFF8D6F28 , dpToPx ( 8 ) ) ) ;
tagLabel . setText ( " 房主 " ) ;
}
}
public void setModel ( BlindBoxBean . xlhUser model ) {
this . model = model ;
// 这里需要根据您的 QXUserModel 类来实现具体逻辑
if ( model instanceof BlindBoxBean . xlhUser ) {
BlindBoxBean . xlhUser userModel = ( BlindBoxBean . xlhUser ) model ;
// 使用图片加载库加载头像
// Glide.with(getContext()).load(userModel.getAvatar()).into(headerImageView);
ImageUtils . loadHeadCC ( userModel . getAvatar ( ) , headerImageView ) ;
nameLabel . setText ( userModel . getNickname ( ) ) ;
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 ( ) {
headerImageView . setImageResource ( R . mipmap . default_avatar ) ;
nameLabel . setText ( " 虚位以待 " ) ;
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 android . graphics . drawable . Drawable getRoundedRectBackground ( int color , float radius ) {
private GradientDrawable getRoundedRectBackground ( int color , float radius ) {
GradientDrawable drawable = new GradientDrawable ( ) ;
drawable . setColor ( color ) ;
drawable . setCornerRadius ( radius ) ;
return drawable ;
}
// 辅助方法: dp 转 px
private int dpToPx ( int dp ) {
float density = getResources ( ) . getDisplayMetrics ( ) . density ;
return Math . round ( dp * density ) ;
}
// Getter 方法
public ImageView getHeaderImageView ( ) {
return header ImageView;
}
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 ) ;
}
}
}
// Getter方法
public ImageView getHeaderImageView ( ) { return headerImageView ; }
public ImageView getDressImageView ( ) { return dress ImageView; }
public TextView getTagLabel ( ) { return tagLabel ; }
public TextView getNameLabel ( ) { return nameLabel ; }
}