You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Jetpack Compose替换AnimationDrawable实现充电动画?

问题描述

原本通过XML视图+AnimationDrawable实现了充电动画:循环切换低电量、中等电量、满电量三张图片,充电时通过TimerTask启动无限循环动画,断开电源时停止。现在要迁移到Jetpack Compose,已经将PNG资源转换为ImageBitmap,但不知道如何替换AnimationDrawable实现同样的效果。

原有Java实现代码:

private class MyTimerTask(private val transitionDrawable: AnimationDrawable) : TimerTask() {
    override fun run() {
        Dispatcher.runOnUiThread {
            transitionDrawable.start()
        }
    }
}

init {
    drawLow = AppCompatResources.getDrawable(context, R.mipmap.low_battery)
    drawMid = AppCompatResources.getDrawable(context, R.mipmap.mid_battery)
    drawFull = AppCompatResources.getDrawable(context, R.mipmap.full_battery)

    if (drawLow !== null && drawMid != null && drawFull != null) {
        mTransitionDrawable.addFrame(drawLow, 500)
        mTransitionDrawable.addFrame(drawMid, 500)
        mTransitionDrawable.addFrame(drawFull, 500)
    }
}

Compose中图片转换代码:

((ResourcesCompat.getDrawable(context.resources, R.mipmap.low_battery, context.theme) as BitmapDrawable).bitmap).asImageBitmap()

实现方案

在Jetpack Compose中,我们可以通过状态管理+协程来实现循环切换图片的动画,完全替代AnimationDrawable的逻辑,步骤如下:

1. 准备图片资源与状态变量

先将三张充电状态的ImageBitmap整理成列表,并用可观察状态跟踪当前显示的图片索引:

val context = LocalContext.current

// 转换图片资源为ImageBitmap,用remember缓存避免重复转换
val lowBattery = remember {
    (ResourcesCompat.getDrawable(context.resources, R.mipmap.low_battery, context.theme) as BitmapDrawable).bitmap.asImageBitmap()
}
val midBattery = remember {
    (ResourcesCompat.getDrawable(context.resources, R.mipmap.mid_battery, context.theme) as BitmapDrawable).bitmap.asImageBitmap()
}
val fullBattery = remember {
    (ResourcesCompat.getDrawable(context.resources, R.mipmap.full_battery, context.theme) as BitmapDrawable).bitmap.asImageBitmap()
}

val batteryImages = listOf(lowBattery, midBattery, fullBattery)
var currentImageIndex by remember { mutableStateOf(0) }

2. 实现循环动画逻辑

用LaunchedEffect配合协程实现定时切换图片的循环逻辑,同时根据充电状态控制动画的启动与停止:

// 实际项目中替换为真实的充电状态监听值
var isCharging by remember { mutableStateOf(false) }

LaunchedEffect(isCharging) {
    if (isCharging) {
        // 充电时无限循环切换图片,每张停留500ms
        while (true) {
            delay(500)
            currentImageIndex = (currentImageIndex + 1) % batteryImages.size
        }
    } else {
        // 停止充电时回到低电量状态(可根据需求调整)
        currentImageIndex = 0
    }
}

3. 显示动画图片

直接根据当前索引从列表中取出对应的ImageBitmap渲染:

Image(
    bitmap = batteryImages[currentImageIndex],
    contentDescription = "充电状态动画",
    modifier = Modifier.size(64.dp) // 根据UI需求调整大小
)

4. 监听充电状态(可选)

如果需要自动响应系统充电状态变化,可以通过BroadcastReceiver结合DisposableEffect实现监听:

DisposableEffect(context) {
    val batteryReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            val batteryStatus = intent?.getIntExtra(BatteryManager.EXTRA_STATUS, -1) ?: -1
            isCharging = batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING || 
                        batteryStatus == BatteryManager.BATTERY_STATUS_FULL
        }
    }
    // 注册电池状态广播监听
    val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
    context.registerReceiver(batteryReceiver, filter)
    
    // 组件销毁时取消注册,避免内存泄漏
    onDispose {
        context.unregisterReceiver(batteryReceiver)
    }
}

方案优势

  • 完全遵循Compose声明式编程模型,无需依赖传统的AnimationDrawable
  • 通过协程和状态管理,动画逻辑更简洁,可控制性更强
  • 天然支持根据充电状态动态启停动画,无需额外处理线程切换

内容的提问来源于stack exchange,提问作者Sebi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 04:14:57