更新盾力热度条视图。修复一些盾值更新问题。
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Fri Dec 12 13:17:41 GMT 2025
|
||||
#Fri Dec 12 17:21:18 GMT 2025
|
||||
stageCount=1
|
||||
libraryProject=
|
||||
baseVersion=15.12
|
||||
publishVersion=15.12.0
|
||||
buildCount=61
|
||||
buildCount=75
|
||||
baseBetaVersion=15.12.1
|
||||
|
||||
@@ -344,10 +344,10 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv
|
||||
initPhoneStateListener();
|
||||
LogUtils.d(TAG, "initUIAndLogic: 电话状态监听器初始化完成");
|
||||
|
||||
// 6. 盾值视图初始化(Java7分步写法,禁止链式调用)
|
||||
DunTemperatureView tempView = (DunTemperatureView) findViewById(R.id.dun_temp_view);
|
||||
tempView.setMaxValue(Rules.getInstance(this).getSettingsModel().getDunTotalCount());
|
||||
tempView.setCurrentValue(Rules.getInstance(this).getSettingsModel().getDunCurrentCount());
|
||||
// 左边盾值视图初始化(Java7分步写法,禁止链式调用)
|
||||
DunTemperatureView tempViewLeft = (DunTemperatureView) findViewById(R.id.dun_temp_view_left);
|
||||
tempViewLeft.setMaxValue(Rules.getInstance(this).getSettingsModel().getDunTotalCount());
|
||||
tempViewLeft.setCurrentValue(Rules.getInstance(this).getSettingsModel().getDunCurrentCount());
|
||||
|
||||
int[] customColors = new int[2];
|
||||
customColors[0] = Color.parseColor("#FF3366FF");
|
||||
@@ -355,7 +355,23 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv
|
||||
float[] positions = new float[2];
|
||||
positions[0] = 0.0f;
|
||||
positions[1] = 1.0f;
|
||||
tempView.setGradientColors(customColors, positions);
|
||||
tempViewLeft.setGradientColors(customColors, positions);
|
||||
// 文本放在温度条右侧(默认,可省略)
|
||||
tempViewLeft.setTextPosition(true);
|
||||
// 右边盾值视图初始化(Java7分步写法,禁止链式调用)
|
||||
DunTemperatureView tempViewRight = (DunTemperatureView) findViewById(R.id.dun_temp_view_right);
|
||||
tempViewRight.setMaxValue(Rules.getInstance(this).getSettingsModel().getDunTotalCount());
|
||||
tempViewRight.setCurrentValue(Rules.getInstance(this).getSettingsModel().getDunCurrentCount());
|
||||
|
||||
// int[] customColors = new int[2];
|
||||
// customColors[0] = Color.parseColor("#FF3366FF");
|
||||
// customColors[1] = Color.parseColor("#FF9900CC");
|
||||
// float[] positions = new float[2];
|
||||
// positions[0] = 0.0f;
|
||||
// positions[1] = 1.0f;
|
||||
tempViewRight.setGradientColors(customColors, positions);
|
||||
// 文本放在温度条左侧
|
||||
tempViewRight.setTextPosition(false);
|
||||
LogUtils.d(TAG, "initUIAndLogic: 盾值视图初始化完成");
|
||||
LogUtils.d(TAG, "===== initUIAndLogic: 初始化流程全部结束 =====");
|
||||
}
|
||||
|
||||
@@ -89,6 +89,9 @@ public class Rules {
|
||||
mSettingsModel.setDunCurrentCount(newDunCount);
|
||||
LogUtils.d(TAG, String.format("设置防御值为%d", newDunCount));
|
||||
saveDun();
|
||||
// 一键更新所有 DunTemperatureView 实例的盾值
|
||||
DunTemperatureView.updateDunValue(mSettingsModel.getDunTotalCount(), mSettingsModel.getDunCurrentCount());
|
||||
|
||||
SettingsActivity.notifyDunInfoUpdate();
|
||||
}
|
||||
}
|
||||
@@ -228,7 +231,7 @@ public class Rules {
|
||||
// 返回校验结果
|
||||
LogUtils.d(TAG, String.format("返回校验结果 isConnect == %s", isConnect));
|
||||
// 一键更新所有 DunTemperatureView 实例的盾值
|
||||
DunTemperatureView.updateDunValue(mSettingsModel.getDunTotalCount(), nDunCurrentCount);
|
||||
DunTemperatureView.updateDunValue(mSettingsModel.getDunTotalCount(), mSettingsModel.getDunCurrentCount());
|
||||
|
||||
return isConnect;
|
||||
}
|
||||
|
||||
@@ -11,27 +11,31 @@ import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/03/19 14:04:20
|
||||
* @Describe 云盾华氏度热力视图,垂直盾值温度视图控件(带颜色渐变+静态Handler更新)
|
||||
* 采用绘图方式展示盾值温度,填充色随盾值比例渐变,底部显示 (当前盾值/最高盾值) 文本
|
||||
* 支持静态方法跨线程发送消息更新视图
|
||||
* 采用绘图方式展示盾值温度,填充色随盾值比例渐变,支持设置文本在温度条左侧/右侧,底部对齐竖排显示
|
||||
* 温度条宽度=5dp,文本区宽度固定=5dp,整体左右边距=0,无任何多余空白间距
|
||||
*/
|
||||
public class DunTemperatureView extends View {
|
||||
// ====================== 常量定义区 ======================
|
||||
public static final String TAG = "DunTemperatureView";
|
||||
// 控件默认尺寸
|
||||
private static final int DEFAULT_WIDTH = 80;
|
||||
// 控件默认高度
|
||||
private static final int DEFAULT_HEIGHT = 200;
|
||||
// 文本预留高度
|
||||
private static final int TEXT_RESERVED_HEIGHT = 40;
|
||||
// 填充区域内边距
|
||||
private static final int FILL_PADDING = 2;
|
||||
// 温度条宽度(5dp)、文本区宽度(固定5dp)
|
||||
private static final int THERMOMETER_WIDTH_DP = 5;
|
||||
private static final int TEXT_AREA_WIDTH_DP = 5;
|
||||
// 填充区域内边距(左右=0,上下=2避免贴边)
|
||||
private static final int FILL_PADDING_HORIZONTAL = 0;
|
||||
private static final int FILL_PADDING_VERTICAL = 2;
|
||||
// 竖排文本字间距
|
||||
private static final float TEXT_CHAR_SPACING = 8f;
|
||||
// Handler消息标识
|
||||
public static final int MSG_UPDATE_DUN_VALUE = 0x01;
|
||||
// 消息参数Key
|
||||
@@ -49,14 +53,17 @@ public class DunTemperatureView extends View {
|
||||
private Paint mThermometerPaint;
|
||||
private Paint mFillPaint;
|
||||
private Paint mTextPaint;
|
||||
// 温度条相关参数
|
||||
// 尺寸参数(dp转px后的值)
|
||||
private int mThermometerWidth;
|
||||
private int mTextAreaWidth;
|
||||
private int mMaxValue = 100; // 最高盾值
|
||||
private int mCurrentValue = 0; // 当前盾值
|
||||
private int mThermometerWidth = 40; // 温度条宽度
|
||||
private RectF mThermometerRect; // 温度条矩形区域
|
||||
// 渐变颜色配置(低→中→高 对应绿→黄→红)
|
||||
private int[] mGradientColors = {Color.GREEN, Color.YELLOW, Color.RED};
|
||||
private float[] mGradientPositions = {0.0f, 0.5f, 1.0f};
|
||||
// 布局配置:true=文本在温度条右侧(默认),false=文本在温度条左侧
|
||||
private boolean isTextOnRight = true;
|
||||
// 其他颜色配置
|
||||
private int mBorderColor = Color.parseColor("#FF444444");
|
||||
private int mTextColor = Color.parseColor("#FF000000");
|
||||
@@ -108,21 +115,27 @@ public class DunTemperatureView extends View {
|
||||
*/
|
||||
private void init() {
|
||||
LogUtils.d(TAG, "init: 开始初始化云盾温度视图控件");
|
||||
// 初始化温度条边框画笔
|
||||
// dp转px(适配不同分辨率)
|
||||
mThermometerWidth = dp2px(getContext(), THERMOMETER_WIDTH_DP);
|
||||
mTextAreaWidth = dp2px(getContext(), TEXT_AREA_WIDTH_DP);
|
||||
LogUtils.d(TAG, "init: 温度条宽度5dp转px=" + mThermometerWidth + ",文本区宽度5dp转px=" + mTextAreaWidth);
|
||||
|
||||
// 温度条边框画笔(宽度1px,适配5dp宽度)
|
||||
mThermometerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mThermometerPaint.setColor(mBorderColor);
|
||||
mThermometerPaint.setStyle(Paint.Style.STROKE);
|
||||
mThermometerPaint.setStrokeWidth(2);
|
||||
mThermometerPaint.setStrokeWidth(1);
|
||||
|
||||
// 初始化温度条填充画笔(支持渐变)
|
||||
// 温度条填充画笔(支持渐变)
|
||||
mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mFillPaint.setStyle(Paint.Style.FILL);
|
||||
|
||||
// 初始化文本画笔
|
||||
// 文本画笔(适配5dp窄文本区,文字居中绘制)
|
||||
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mTextPaint.setColor(mTextColor);
|
||||
mTextPaint.setTextSize(30);
|
||||
mTextPaint.setTextSize(18); // 缩小字号适配5dp窄文本区(避免文字超出)
|
||||
mTextPaint.setTextAlign(Paint.Align.CENTER);
|
||||
mTextPaint.setFakeBoldText(true); // 文字加粗,提升窄区域可读性
|
||||
|
||||
// 初始化温度条矩形
|
||||
mThermometerRect = new RectF();
|
||||
@@ -132,6 +145,36 @@ public class DunTemperatureView extends View {
|
||||
LogUtils.d(TAG, "init: 云盾温度视图控件初始化完成,实例已加入缓存");
|
||||
}
|
||||
|
||||
// ====================== 工具方法区 ======================
|
||||
/**
|
||||
* dp 转 px(适配不同屏幕分辨率)
|
||||
*/
|
||||
private int dp2px(Context context, float dpValue) {
|
||||
return (int) TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
dpValue,
|
||||
context.getResources().getDisplayMetrics()
|
||||
);
|
||||
}
|
||||
|
||||
// ====================== 对外控制方法区 ======================
|
||||
/**
|
||||
* 设置文本相对于温度条的位置
|
||||
* @param isOnRight true=文本在温度条右侧(默认),false=文本在温度条左侧
|
||||
*/
|
||||
public void setTextPosition(boolean isOnRight) {
|
||||
this.isTextOnRight = isOnRight;
|
||||
invalidate(); // 刷新布局绘制
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前文本位置配置
|
||||
* @return true=右侧,false=左侧
|
||||
*/
|
||||
public boolean isTextOnRight() {
|
||||
return isTextOnRight;
|
||||
}
|
||||
|
||||
// ====================== 对外静态方法区 ======================
|
||||
/**
|
||||
* 静态外部方法:发送消息更新所有 DunTemperatureView 实例的盾值
|
||||
@@ -165,7 +208,6 @@ public class DunTemperatureView extends View {
|
||||
this.mMaxValue = maxValue;
|
||||
// 限制当前值不超过最大值
|
||||
mCurrentValue = Math.min(mCurrentValue, maxValue);
|
||||
LogUtils.d(TAG, "setMaxValue: 最高盾值设置为" + maxValue + ",当前值校准为" + mCurrentValue);
|
||||
invalidate(); // 重绘控件
|
||||
}
|
||||
|
||||
@@ -260,69 +302,92 @@ public class DunTemperatureView extends View {
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
// 设置控件默认尺寸
|
||||
int width = measureSize(DEFAULT_WIDTH, widthMeasureSpec);
|
||||
// 强制控件整体左右内边距=0,彻底消除外部边距
|
||||
setPadding(0, getPaddingTop(), 0, getPaddingBottom());
|
||||
|
||||
// 控件宽度=温度条宽度 + 文本区宽度(均为5dp转px,无额外空白)
|
||||
int defaultWidth = mThermometerWidth + mTextAreaWidth;
|
||||
int width = measureSize(defaultWidth, widthMeasureSpec);
|
||||
int height = measureSize(DEFAULT_HEIGHT, heightMeasureSpec);
|
||||
setMeasuredDimension(width, height);
|
||||
|
||||
// 计算温度条矩形区域(居中绘制)
|
||||
int paddingLeft = getPaddingLeft();
|
||||
int paddingRight = getPaddingRight();
|
||||
int paddingTop = getPaddingTop();
|
||||
int paddingBottom = getPaddingBottom();
|
||||
// 根据文本位置配置,计算温度条矩形坐标
|
||||
float thermometerLeft, thermometerRight;
|
||||
if (isTextOnRight) {
|
||||
// 文本在右侧:温度条靠左,右接文本区
|
||||
thermometerLeft = 0;
|
||||
thermometerRight = thermometerLeft + mThermometerWidth;
|
||||
} else {
|
||||
// 文本在左侧:温度条靠右,左接文本区
|
||||
thermometerLeft = width - mThermometerWidth;
|
||||
thermometerRight = width;
|
||||
}
|
||||
float thermometerTop = getPaddingTop();
|
||||
float thermometerBottom = height - getPaddingBottom();
|
||||
mThermometerRect.set(thermometerLeft, thermometerTop, thermometerRight, thermometerBottom);
|
||||
|
||||
int contentWidth = width - paddingLeft - paddingRight;
|
||||
int contentHeight = height - paddingTop - paddingBottom - TEXT_RESERVED_HEIGHT;
|
||||
|
||||
float left = paddingLeft + (contentWidth - mThermometerWidth) / 2f;
|
||||
float right = left + mThermometerWidth;
|
||||
float top = paddingTop;
|
||||
float bottom = top + contentHeight;
|
||||
|
||||
mThermometerRect.set(left, top, right, bottom);
|
||||
LogUtils.v(TAG, "onMeasure: 温度条矩形区域设置为" + mThermometerRect.toShortString());
|
||||
LogUtils.v(TAG, "onMeasure: 文本位置=" + (isTextOnRight ? "右侧" : "左侧") + ",控件尺寸=" + width + "x" + height + ",温度条区域=" + mThermometerRect.toShortString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
// 绘制温度条边框
|
||||
canvas.drawRoundRect(mThermometerRect, 10, 10, mThermometerPaint);
|
||||
// 1. 绘制温度条边框(5dp宽度,小圆角适配)
|
||||
canvas.drawRoundRect(mThermometerRect, 3, 3, mThermometerPaint);
|
||||
|
||||
// 计算填充高度(根据当前值占最大值的比例)
|
||||
// 2. 计算填充高度(根据当前值占最大值的比例)
|
||||
float fillRatio = (float) mCurrentValue / mMaxValue;
|
||||
float fillHeight = mThermometerRect.height() * fillRatio;
|
||||
float fillTop = mThermometerRect.bottom - fillHeight;
|
||||
|
||||
// 绘制渐变填充部分
|
||||
// 3. 绘制渐变填充部分(左右贴边框,无间距)
|
||||
if (fillHeight > 0) {
|
||||
RectF fillRect = new RectF(
|
||||
mThermometerRect.left + FILL_PADDING,
|
||||
fillTop,
|
||||
mThermometerRect.right - FILL_PADDING,
|
||||
mThermometerRect.bottom
|
||||
mThermometerRect.left + FILL_PADDING_HORIZONTAL,
|
||||
fillTop + FILL_PADDING_VERTICAL,
|
||||
mThermometerRect.right - FILL_PADDING_HORIZONTAL,
|
||||
mThermometerRect.bottom - FILL_PADDING_VERTICAL
|
||||
);
|
||||
// 创建线性渐变(从下到上,对应盾值低到高)
|
||||
LinearGradient gradient = new LinearGradient(
|
||||
fillRect.centerX(), fillRect.bottom,
|
||||
fillRect.centerX(), fillRect.top,
|
||||
mGradientColors,
|
||||
mGradientPositions,
|
||||
Shader.TileMode.CLAMP
|
||||
fillRect.centerX(), fillRect.bottom,
|
||||
fillRect.centerX(), fillRect.top,
|
||||
mGradientColors,
|
||||
mGradientPositions,
|
||||
Shader.TileMode.CLAMP
|
||||
);
|
||||
mFillPaint.setShader(gradient);
|
||||
canvas.drawRoundRect(fillRect, 8, 8, mFillPaint);
|
||||
// 用完渐变后清空shader,避免影响后续绘制
|
||||
canvas.drawRoundRect(fillRect, 2, 2, mFillPaint);
|
||||
mFillPaint.setShader(null);
|
||||
LogUtils.v(TAG, "onDraw: 渐变填充绘制完成,填充高度=" + fillHeight + ",比例=" + fillRatio);
|
||||
}
|
||||
|
||||
// 绘制底部文本 (当前盾值/最高盾值)
|
||||
String text = String.format("(%d/%d)", mCurrentValue, mMaxValue);
|
||||
float textX = getWidth() / 2f;
|
||||
float textY = mThermometerRect.bottom + 30;
|
||||
canvas.drawText(text, textX, textY, mTextPaint);
|
||||
LogUtils.v(TAG, "onDraw: 底部文本绘制完成,内容=" + text);
|
||||
// 4. 绘制文本(5dp固定宽度文本区,底部对齐竖排,文字居中)
|
||||
String text = String.format("%d/%d", mCurrentValue, mMaxValue);
|
||||
if (text.isEmpty()) return;
|
||||
|
||||
float textBaseX;
|
||||
if (isTextOnRight) {
|
||||
// 文本在右侧:X=温度条右边缘 + 文本区宽度的一半(紧贴温度条)
|
||||
textBaseX = mThermometerRect.right + (mTextAreaWidth / 2f);
|
||||
} else {
|
||||
// 文本在左侧:X=文本区宽度的一半(紧贴控件左边缘)
|
||||
textBaseX = mTextAreaWidth / 2f;
|
||||
}
|
||||
|
||||
// 文本绘制参数(适配5dp窄区域,缩小字间距提升紧凑度)
|
||||
float singleCharHeight = mTextPaint.getTextSize() + (TEXT_CHAR_SPACING - 2f); // 字间距减为6f
|
||||
float totalTextHeight = (singleCharHeight * text.length()) - (TEXT_CHAR_SPACING - 2f);
|
||||
Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
|
||||
float charBottomOffset = fontMetrics.bottom;
|
||||
|
||||
// 文本起始Y(底部对齐控件底部,无间距)
|
||||
float startTextY = getHeight() - getPaddingBottom() - charBottomOffset;
|
||||
|
||||
// 逐字竖排绘制(文字居中于5dp文本区,无超出)
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
char singleChar = text.charAt(i);
|
||||
float currentTextY = startTextY - (i * singleCharHeight);
|
||||
canvas.drawText(String.valueOf(singleChar), textBaseX, currentTextY, mTextPaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,12 +21,13 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.0"
|
||||
android:padding="10dp">
|
||||
android:paddingTop="10dp"
|
||||
android:paddingBottom="10dp">
|
||||
|
||||
<cc.winboll.studio.contacts.views.DunTemperatureView
|
||||
android:layout_width="50dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/dun_temp_view"
|
||||
android:id="@+id/dun_temp_view_left"
|
||||
android:layout_alignParentLeft="true"/>
|
||||
|
||||
<LinearLayout
|
||||
@@ -34,8 +35,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/activitymainLinearLayout1"
|
||||
android:layout_toRightOf="@id/dun_temp_view"
|
||||
android:layout_alignParentRight="true">
|
||||
android:layout_toRightOf="@id/dun_temp_view_left"
|
||||
android:layout_toLeftOf="@id/dun_temp_view_right">
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:layout_width="match_parent"
|
||||
@@ -50,6 +51,12 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<cc.winboll.studio.contacts.views.DunTemperatureView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/dun_temp_view_right"
|
||||
android:layout_alignParentRight="true"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
Reference in New Issue
Block a user