添加BatteryStyleView控件,添加能量与斑马绘图风格。

This commit is contained in:
2025-12-27 21:12:54 +08:00
parent fca17908b2
commit abd956d7d0
8 changed files with 356 additions and 36 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Sat Dec 27 14:48:34 HKT 2025
#Sat Dec 27 13:11:18 GMT 2025
stageCount=38
libraryProject=
baseVersion=15.14
publishVersion=15.14.37
buildCount=0
buildCount=23
baseBetaVersion=15.14.38

View File

@@ -0,0 +1,11 @@
package cc.winboll.studio.powerbell.models;
/**
* 电池绘制样式枚举 (单选选项)
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
*/
public enum BatteryStyle {
ZEBRA_STYLE, // 条纹样式
ENERGY_STYLE // 能量样式
}

View File

@@ -7,6 +7,7 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.models.BatteryStyle;
/**
* 电池电量Drawable适配API30兼容小米机型支持能量/条纹两种绘制风格切换
@@ -31,7 +32,7 @@ public class BatteryDrawable extends Drawable {
private final Paint mBatteryPaint;
// 业务控制变量
private int mBatteryValue = -1; // 当前电量0-100-1=未初始化)
private boolean mIsEnergyStyle = true; // 绘制风格true=能量false=条纹)
private BatteryStyle mBatteryStyle = BatteryStyle.ENERGY_STYLE; // 绘制风格true=能量false=条纹)
// ====================================== 构造方法(重载适配,优先暴露常用构造) ======================================
/**
@@ -49,13 +50,16 @@ public class BatteryDrawable extends Drawable {
* @param batteryColor 电量显示颜色
* @param isEnergyStyle 是否启用能量风格
*/
public BatteryDrawable(int batteryColor, boolean isEnergyStyle) {
LogUtils.d(TAG, "【BatteryDrawable】构造器2调用 | 颜色=" + Integer.toHexString(batteryColor) + " | 风格=" + (isEnergyStyle ? "能量" : "条纹"));
public BatteryDrawable(int batteryColor, BatteryStyle batteryStyle) {
mBatteryPaint = new Paint();
mIsEnergyStyle = isEnergyStyle;
mBatteryStyle = batteryStyle;
initPaintConfig(batteryColor);
}
public void setIsEnergyStyle(BatteryStyle batteryStyle) {
this.mBatteryStyle = batteryStyle;
}
// ====================================== 私有初始化方法(封装复用,隐藏内部逻辑) ======================================
/**
* 初始化画笔配置适配API30渲染特性优化小米机型兼容性
@@ -74,8 +78,7 @@ public class BatteryDrawable extends Drawable {
// ====================================== 核心绘制方法Drawable抽象方法优先级最高 ======================================
@Override
public void draw(Canvas canvas) {
LogUtils.d(TAG, "【draw】绘制开始 | 当前电量=" + mBatteryValue + " | 风格=" + (mIsEnergyStyle ? "能量" : "条纹"));
// 未初始化/异常电量,直接跳过,避免无效绘制
// 未初始化/异常电量,直接跳过,避免无效绘制
if (mBatteryValue < 0) {
LogUtils.w(TAG, "【draw】电量未初始化跳过绘制");
return;
@@ -99,10 +102,10 @@ public class BatteryDrawable extends Drawable {
LogUtils.d(TAG, "【draw】绘制参数校准 | 左边界=" + left + " | 右边界=" + right + " | 高度=" + drawHeight);
// 按风格执行绘制
if (mIsEnergyStyle) {
if (mBatteryStyle == BatteryStyle.ENERGY_STYLE) {
drawEnergyStyle(canvas, validBattery, left, right, drawHeight);
} else {
drawStripeStyle(canvas, validBattery, left, right, drawHeight);
} else if (mBatteryStyle == BatteryStyle.ZEBRA_STYLE) {
drawZebraStyle(canvas, validBattery, left, right, drawHeight);
}
LogUtils.d(TAG, "【draw】绘制完成");
}
@@ -131,15 +134,32 @@ public class BatteryDrawable extends Drawable {
* @param right 右边界
* @param height 绘制高度
*/
private void drawStripeStyle(Canvas canvas, int battery, int left, int right, int height) {
private void drawZebraStyle(Canvas canvas, int battery, int left, int right, int height) {
LogUtils.d(TAG, "【drawStripeStyle】条纹风格绘制开始 | 电量=" + battery);
int stripeHeight = height / STRIPE_COUNT; // 单条条纹高度(均匀拆分)
// 从底部向上绘制对应电量条纹
for (int i = 0; i < battery; i++) {
int bottom = height - (stripeHeight * i);
int top = bottom - stripeHeight;
canvas.drawRect(new Rect(left, top, right, bottom), mBatteryPaint);
}
// int stripeHeight = height / STRIPE_COUNT; // 单条条纹高度(均匀拆分)
// // 从底部向上绘制对应电量条纹
// for (int i = 0; i < battery; i++) {
// int bottom = height - (stripeHeight * i);
// int top = bottom - stripeHeight;
// canvas.drawRect(new Rect(left, top, right, bottom), mBatteryPaint);
// }
int nWidth = getBounds().width();
int nHeight = getBounds().height();
int mnDx = nHeight / 203;
// 意兴阑珊绘图风格
int nTop;
int nLeft = 0;
int nBottom;
int nRight = nWidth;
for (int i = 0; i < mBatteryValue; i ++) {
nBottom = (nHeight * (100 - i) / 100) - mnDx;
nTop = nBottom + mnDx;
canvas.drawRect(new Rect(nLeft, nTop, nRight, nBottom), mBatteryPaint);
}
LogUtils.d(TAG, "【drawStripeStyle】条纹风格绘制完成 | 条纹数量=" + battery);
}
@@ -159,9 +179,8 @@ public class BatteryDrawable extends Drawable {
* 切换绘制风格
* @param isEnergyStyle true=能量风格false=条纹风格
*/
public void switchDrawStyle(boolean isEnergyStyle) {
LogUtils.d(TAG, "【switchDrawStyle】风格切换 | 旧风格=" + (mIsEnergyStyle ? "能量" : "条纹") + " | 新风格=" + (isEnergyStyle ? "能量" : "条纹"));
mIsEnergyStyle = isEnergyStyle;
public void setDrawStyle(BatteryStyle batteryStyle) {
mBatteryStyle = batteryStyle;
invalidateSelf();
LogUtils.d(TAG, "【switchDrawStyle】已触发重绘");
}
@@ -188,12 +207,10 @@ public class BatteryDrawable extends Drawable {
return mBatteryValue;
}
/**
* 获取当前绘制风格
* @return true=能量风格false=条纹风格
*/
public boolean isEnergyStyle() {
return mIsEnergyStyle;
public BatteryStyle getEnergyStyle() {
return mBatteryStyle;
}
// ====================================== Drawable抽象方法必须实现精简逻辑 ======================================

View File

@@ -0,0 +1,195 @@
package cc.winboll.studio.powerbell.views;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RelativeLayout;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.models.BatteryStyle;
/**
* 电池样式单选视图水平展示所有BatteryStyle枚举选项
* 每个选项 = RadioButton单选按钮 + BatteryDrawable预览控件
* 适配API30、Java7规范联动BatteryDrawable绘制样式
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
*/
public class BatteryStyleView extends LinearLayout implements RadioGroup.OnCheckedChangeListener {
// ====================== 常量区 ======================
public static final String TAG = "BatteryStyleView";
private static final int DEFAULT_BATTERY_COLOR = Color.parseColor("#FF4CAF50");
private static final int DEFAULT_CHECKED_STYLE_INDEX = 0; // 默认选中第一个
// ====================== 控件变量 ======================
private RadioGroup rgBatteryStyle;
private RadioButton rbZebraStyle;
private RadioButton rbEnergyStyle;
private RelativeLayout rlZebraPreview;
private RelativeLayout rlEnergyPreview;
// 预览用的BatteryDrawable
private BatteryDrawable mZebraDrawable;
private BatteryDrawable mEnergyDrawable;
// ====================== 业务变量 ======================
private BatteryStyle mCurrentStyle = BatteryStyle.ZEBRA_STYLE; // 当前选中样式
private OnBatteryStyleSelectedListener mStyleSelectedListener; // 选中回调
private int mBatteryColor = DEFAULT_BATTERY_COLOR; // 预览颜色
private int mBatteryValue = 100; // 预览默认电量值
// ====================== 构造方法 ======================
public BatteryStyleView(Context context) {
super(context);
initView(context, null);
}
public BatteryStyleView(Context context, AttributeSet attrs) {
super(context, attrs);
initAttrs(context, attrs);
initView(context, attrs);
}
public BatteryStyleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(context, attrs);
initView(context, attrs);
}
// ====================== 初始化方法 ======================
/**
* 解析自定义属性
*/
private void initAttrs(Context context, AttributeSet attrs) {
if (attrs == null) return;
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BatteryStyleView);
mBatteryColor = typedArray.getColor(R.styleable.BatteryStyleView_batteryPreviewColor, DEFAULT_BATTERY_COLOR);
mBatteryValue = typedArray.getInt(R.styleable.BatteryStyleView_previewBatteryValue, 100);
int styleIndex = typedArray.getInt(R.styleable.BatteryStyleView_defaultSelectedStyle, DEFAULT_CHECKED_STYLE_INDEX);
mCurrentStyle = styleIndex == 0 ? BatteryStyle.ZEBRA_STYLE : BatteryStyle.ENERGY_STYLE;
typedArray.recycle();
LogUtils.d(TAG, "【initAttrs】解析属性完成 电量颜色=" + Integer.toHexString(mBatteryColor) + " 预览电量=" + mBatteryValue + " 默认样式=" + mCurrentStyle.name());
}
/**
* 初始化布局+控件+监听
*/
private void initView(Context context, AttributeSet attrs) {
// 加载XML布局文件
LayoutInflater.from(context).inflate(R.layout.view_battery_style, this, true);
// 绑定控件
rgBatteryStyle = findViewById(R.id.rg_battery_style);
rbZebraStyle = findViewById(R.id.rb_zebra_style);
rbEnergyStyle = findViewById(R.id.rb_energy_style);
rlZebraPreview = findViewById(R.id.rl_zebra_preview);
rlEnergyPreview = findViewById(R.id.rl_energy_preview);
// 初始化预览Drawable
initPreviewDrawable();
// 设置单选监听
rgBatteryStyle.setOnCheckedChangeListener(this);
// 设置默认选中
setDefaultChecked();
LogUtils.d(TAG, "【initView】视图初始化完成");
}
/**
* 初始化两个预览用的BatteryDrawable
* ZEBRA_STYLE → 对应BatteryDrawable的STRIPE_STYLE
* ENERGY_STYLE → 对应BatteryDrawable的ENERGY_STYLE
*/
private void initPreviewDrawable() {
// 条纹样式预览
mZebraDrawable = new BatteryDrawable(mBatteryColor, BatteryStyle.ZEBRA_STYLE);
mZebraDrawable.setBatteryValue(mBatteryValue);
rlZebraPreview.setBackground(mZebraDrawable);
// 能量样式预览
mEnergyDrawable = new BatteryDrawable(mBatteryColor, BatteryStyle.ENERGY_STYLE);
mEnergyDrawable.setBatteryValue(mBatteryValue);
rlEnergyPreview.setBackground(mEnergyDrawable);
LogUtils.d(TAG, "【initPreviewDrawable】Drawable预览初始化完成");
}
/**
* 设置默认选中项
*/
private void setDefaultChecked() {
if (mCurrentStyle == BatteryStyle.ZEBRA_STYLE) {
rbZebraStyle.setChecked(true);
} else {
rbEnergyStyle.setChecked(true);
}
}
// ====================== RadioGroup选中回调 ======================
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (checkedId == R.id.rb_zebra_style) {
mCurrentStyle = BatteryStyle.ZEBRA_STYLE;
LogUtils.d(TAG, "【onCheckedChanged】选中样式 → " + mCurrentStyle.name());
} else if (checkedId == R.id.rb_energy_style) {
mCurrentStyle = BatteryStyle.ENERGY_STYLE;
LogUtils.d(TAG, "【onCheckedChanged】选中样式 → " + mCurrentStyle.name());
}
// 回调外部监听
if (mStyleSelectedListener != null) {
mStyleSelectedListener.onStyleSelected(mCurrentStyle);
}
}
// ====================== 对外暴露方法 ======================
/**
* 设置选中的样式
*/
public void setSelectedStyle(BatteryStyle style) {
mCurrentStyle = style;
if (style == BatteryStyle.ZEBRA_STYLE) {
rbZebraStyle.setChecked(true);
} else {
rbEnergyStyle.setChecked(true);
}
LogUtils.d(TAG, "【setSelectedStyle】手动设置选中样式 → " + style.name());
}
/**
* 获取当前选中的样式
*/
public BatteryStyle getCurrentStyle() {
return mCurrentStyle;
}
/**
* 设置预览的电量值
*/
public void setPreviewBatteryValue(int batteryValue) {
this.mBatteryValue = batteryValue;
mZebraDrawable.setBatteryValue(batteryValue);
mEnergyDrawable.setBatteryValue(batteryValue);
}
/**
* 设置预览的电池颜色
*/
public void setPreviewBatteryColor(int color) {
this.mBatteryColor = color;
mZebraDrawable.updateBatteryColor(color);
mEnergyDrawable.updateBatteryColor(color);
}
/**
* 设置选中回调监听
*/
public void setOnBatteryStyleSelectedListener(OnBatteryStyleSelectedListener listener) {
this.mStyleSelectedListener = listener;
}
// ====================== 选中回调接口 ======================
public interface OnBatteryStyleSelectedListener {
void onStyleSelected(BatteryStyle batteryStyle);
}
}

View File

@@ -113,8 +113,9 @@
<LinearLayout
android:orientation="vertical"
android:layout_width="80dp"
android:layout_height="match_parent">
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.0">
<TextView
android:layout_width="match_parent"
@@ -127,7 +128,7 @@
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="0dp"
android:id="@+id/fragmentandroidviewImageView2"
android:layout_weight="1.0"/>
@@ -135,7 +136,7 @@
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.0">
@@ -150,7 +151,7 @@
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="0dp"
android:id="@+id/fragmentandroidviewImageView1"
android:layout_weight="1.0"/>
@@ -158,8 +159,9 @@
<LinearLayout
android:orientation="vertical"
android:layout_width="80dp"
android:layout_height="match_parent">
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.0">
<TextView
android:layout_width="match_parent"
@@ -172,7 +174,7 @@
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="0dp"
android:id="@+id/fragmentandroidviewImageView3"
android:layout_weight="1.0"/>

View File

@@ -33,5 +33,20 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0">
<cc.winboll.studio.powerbell.views.BatteryStyleView
android:id="@+id/battery_style_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:batteryPreviewColor="@color/colorPrimary"
app:previewBatteryValue="100"
app:defaultSelectedStyle="zebra_style"/>
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<RadioGroup
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rg_battery_style"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="8dp"
android:spacing="16dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center_horizontal"
android:padding="4dp">
<RadioButton
android:id="@+id/rb_zebra_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/zebra_style"
android:textSize="14sp"
android:buttonTint="@color/colorPrimary"
android:textColor="@color/colorPrimary"/>
<RelativeLayout
android:id="@+id/rl_zebra_preview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#F5F5F5"
android:padding="1dp"
android:layout_weight="1.0"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center_horizontal"
android:padding="4dp">
<RadioButton
android:id="@+id/rb_energy_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/energy_style"
android:textSize="14sp"
android:buttonTint="@color/colorPrimary"
android:textColor="@color/colorPrimary"/>
<RelativeLayout
android:id="@+id/rl_energy_preview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#F5F5F5"
android:padding="1dp"
android:layout_weight="1.0"/>
</LinearLayout>
</RadioGroup>

View File

@@ -1,3 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- BatteryStyleView 自定义属性 -->
<declare-styleable name="BatteryStyleView">
<attr name="batteryPreviewColor" format="color"/>
<attr name="previewBatteryValue" format="integer"/>
<attr name="defaultSelectedStyle" format="integer">
<enum name="zebra_style" value="0"/>
<enum name="energy_style" value="1"/>
</attr>
</declare-styleable>
<!-- 字符串资源可放到strings.xml -->
<string name="zebra_style">Zebra Style</string>
<string name="energy_style">Energy Style</string>
</resources>