当前位置: 首页 > news >正文

Android 自定义电池组件(BatteryView)

支持:

  • XML 与代码动态设置电量(0–100)

  • 充电 charging 与快充 fastCharging 区分(闪电样式 + 动画)

  • 电量阈值自动配色:<20% 红、<50% 橙、≥50% 绿

  • 可配置边框/轨道/电量/闪电颜色;可显示百分比文本

  • 支持无障碍(contentDescription、AccessibilityLiveRegion)

  • 支持状态保存(旋转/进程重建)

  • 平滑动画过渡(setLevelAnimated)

1、自定义属性 res/values/attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="BatteryView">
<attr name="bv_level" format="integer"/>
<attr name="bv_showPercentage" format="boolean"/>
<attr name="bv_charging" format="boolean"/>
<attr name="bv_fastCharging" format="boolean"/><attr name="bv_borderColor" format="color"/>
<attr name="bv_trackColor" format="color"/>
<attr name="bv_fillColor" format="color"/>
<attr name="bv_lowColor" format="color"/>
<attr name="bv_mediumColor" format="color"/>
<attr name="bv_highColor" format="color"/>
<attr name="bv_boltColor" format="color"/><attr name="bv_borderWidth" format="dimension"/>
<attr name="bv_cornerRadius" format="dimension"/>
<attr name="bv_capWidth" format="dimension"/>
<attr name="bv_capGap" format="dimension"/>
<attr name="bv_textSize" format="dimension"/>
</declare-styleable>
</resources>

术语说明:

  • borderColor:电池外框线条颜色。

  • trackColor:电池内部“轨道/背景”颜色(未被电量填充区域)。

  • fillColor:电量填充的基础颜色(当未启用分段阈值或外部强制指定时)。

2、 组件代码 BatteryView.kt

package com.yourpkg.widget
val y6 = t + h * 0.35fboltPath.reset()
boltPath.moveTo(x1, y1)
boltPath.lineTo(x2, y2)
boltPath.lineTo(x3, y3)
boltPath.lineTo(x4, y4)
boltPath.lineTo(x5, y5)
boltPath.lineTo(x6, y6)
boltPath.close()
}
// endregion// region — Accessibility
private fun updateContentDesc() {
val charge = when {
fastCharging -> "(快充中)"
charging -> "(充电中)"
else -> ""
}
contentDescription = "电量 $level%$charge"
}
// endregion// region — State
override fun onSaveInstanceState(): Parcelable? {
val superState = super.onSaveInstanceState()
return SavedState(superState).also {
it.level = level
it.charging = charging
it.fastCharging = fastCharging
it.showPercentage = showPercentage
it.chargePulse = chargePulse
}
}override fun onRestoreInstanceState(state: Parcelable?) {
val ss = state as? SavedState
super.onRestoreInstanceState(ss?.superState ?: state)
ss?.let {
level = it.level
charging = it.charging
fastCharging = it.fastCharging
showPercentage = it.showPercentage
chargePulse = it.chargePulse
toggleChargeAnim(charging)
}
}private class SavedState : BaseSavedState {
var level: Int = 0
var charging: Boolean = false
var fastCharging: Boolean = false
var showPercentage: Boolean = false
var chargePulse: Float = 0fconstructor(superState: Parcelable?) : super(superState)
private constructor(inParcel: Parcel) : super(inParcel) {
level = inParcel.readInt()
charging = inParcel.readInt() == 1
fastCharging = inParcel.readInt() == 1
showPercentage = inParcel.readInt() == 1
chargePulse = inParcel.readFloat()
}
override fun writeToParcel(out: Parcel, flags: Int) {
super.writeToParcel(out, flags)
out.writeInt(level)
out.writeInt(if (charging) 1 else 0)
out.writeInt(if (fastCharging) 1 else 0)
out.writeInt(if (showPercentage) 1 else 0)
out.writeFloat(chargePulse)
}
companion object {
@JvmField val CREATOR: Parcelable.Creator<SavedState> = object : Parcelable.Creator<SavedState> {
override fun createFromParcel(source: Parcel): SavedState = SavedState(source)
override fun newArray(size: Int): Array<SavedState?> = arrayOfNulls(size)
}
}
}
// endregion// region — Utils
private fun dp(v: Float) = v * resources.displayMetrics.density
private fun sp(v: Float) = v * resources.displayMetrics.scaledDensity
// endregion
}

3、XML 用法示例

<com.yourpkg.widget.BatteryView
android:id="@+id/battery"
android:layout_width="120dp"
android:layout_height="40dp"
android:layout_margin="16dp"
app:bv_level="45"
app:bv_showPercentage="true"
app:bv_charging="true"
app:bv_fastCharging="false"app:bv_borderColor="#222222"
app:bv_trackColor="#F2F2F2"
app:bv_lowColor="#E53935"
app:bv_mediumColor="#FB8C00"
app:bv_highColor="#43A047"
app:bv_boltColor="#FFFFFF"app:bv_borderWidth="2dp"
app:bv_cornerRadius="8dp"
app:bv_capWidth="7dp"
app:bv_capGap="2dp"
app:bv_textSize="12sp"/>

4、代码控制示例

val bv = findViewById<BatteryView>(R.id.battery)// 动态设置电量
bv.level = 18 // 立即刷新
bv.setLevelAnimated(76) // 平滑动画到 76%// 充电状态
bv.charging = true // 显示闪电 + 呼吸动画
bv.fastCharging = true // 闪电更大、视觉更强// 开关百分比
bv.showPercentage = false// 结合业务:阈值配色自动处理(<20 红、<50 橙、≥50 绿),无需额外代码

5、常见问题(结合你之前的疑问)

  • Q: borderColor 和 trackColor 是什么?
    A: borderColor 是外框线条;trackColor 是内部未充满的背景。

  • Q: 无障碍报错 isImportantForAccessibility
    A: 组件内已设置:

    importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES

    accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_POLITE

    同时动态更新 contentDescription,读屏会播报“电量 76%,快充中”。

  • Q: 如何自定义颜色?
    在 XML 传入 bv_lowColor/bv_mediumColor/bv_highColor,或在代码里直接修改。

  • Q: 性能如何?
    组件绘制简单,动画为轻量级呼吸,postOnAnimation 驱动,开销极低。

6、小扩展(可选)

  • 电量渐变色:将 fillPaint 设置为 LinearGradient,根据 level 动态改变 endX。

  • 低电量闪烁:level<10 且非充电时,使用 alpha 在 120–255 之间脉动。

  • RTL 适配:当 layoutDirection == LAYOUT_DIRECTION_RTL 时从右向左填充(可根据需要调整 fillRect 计算)。

http://www.dtcms.com/a/393620.html

相关文章:

  • 基于 Stripe/Metering 的用量计费:从 SLO 指标到账单流水
  • 如何解决 pip install 安装报错 ModuleNotFoundError: No module named ‘fastapi’ 问题
  • 论文阅读——隧道中毫米波MIMO信道特性的实验研究
  • The Library: 1靶场渗透
  • 23种设计模式之【装饰器模式】-核心原理与 Java实践
  • 动态规划中的背包问题:0/1 背包与完全背包的核心解析
  • PHP应用-组件框架前端模版渲染三方插件富文本编辑器CVE审计(2024小迪安全DAY30笔记)
  • uniapp 如何判断发的请求是网络异常uni.request
  • 学习:uniapp全栈微信小程序vue3后台 (25)
  • 23种设计模式之【原型模式】-核心原理与 Java实践
  • Netty 重放解码器ReplayingDecoder揭秘:重写轻量异常机制 和 ConstantPool
  • getgeo 生物信息 R语言 表型信息表”“样本信息表”或“临床信息表 phenodata phenotype data
  • OceanBase备租户创建(二):通过BACKUP DATABASE PLUS ARCHIVELOG
  • Linux文件打包压缩与软件安装管理完全指南
  • KingbaseES数据备份操作详解(图文教程)
  • 中断屏蔽实现方法-ARM内核
  • Kotlin 协程之 SharedFlow 与 StateFlow 深度解析
  • python爬虫(请求+解析+案例)
  • 111-Christopher-Dall_Arm-Timers-and-Fire:Arm架构计时器与半虚拟化时间
  • switch缺少break出现bug
  • 【自然语言处理】(3) --RNN循环神经网络
  • C# 中的 ReferenceEquals 方法
  • BERT:用于语言理解的深度双向Transformer预训练【简单分析】
  • 力扣hot100:两数相加(模拟竖式加法详解)(2)
  • Zotero + Word 插件管理参考文献的引用
  • 用Python一键整理文件:自动分类DOCX与PDF,告别文件夹杂乱
  • Ubuntu部署Elasticsearch教程
  • 61.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--新增功能--提取金额
  • 一款基于 .NET 开源、免费、命令行式的哔哩哔哩视频内容下载工具
  • Win Semi宣布推出线性优化的GaN工艺