Android音频录制播放动画实现:Telegram已播放区域填充方案问询
Android实现Telegram风格音频播放进度填充效果
嘿,关于你想做的这种音频录制/播放视图的已播放部分填充效果(就像Telegram那样,初始灰色,播放过的区域变蓝色),我刚好有几个实用的方案可以分享给你,而且比你最初设想的两张图+FrameLayout要更灵活可控哦~
方案一:用LayerDrawable + ClipDrawable快速实现(无需自定义View)
这个方案适合快速落地,不用写自定义View的代码,完全靠Drawable配置就能搞定:
准备基础Drawable资源
- 先做一个灰色的未播放背景(带圆角,贴合Telegram的风格),比如
res/drawable/audio_bg_gray.xml:<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#E0E0E0"/> <corners android:radius="16dp"/> </shape> - 再做一个蓝色的已播放前景,
res/drawable/audio_bg_blue.xml:<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#2196F3"/> <corners android:radius="16dp"/> </shape>
- 先做一个灰色的未播放背景(带圆角,贴合Telegram的风格),比如
创建LayerDrawable组合+ClipDrawable控制显示
新建res/drawable/audio_progress_drawable.xml,把蓝色前景用ClipDrawable包裹,放在灰色背景上层:<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 底层:灰色未播放背景 --> <item android:drawable="@drawable/audio_bg_gray"/> <!-- 上层:蓝色已播放部分,用ClipDrawable控制显示比例 --> <item> <clip android:drawable="@drawable/audio_bg_blue" android:clipOrientation="horizontal" android:gravity="left"/> </item> </layer-list>在布局和代码中使用
布局里用ImageView加载这个drawable:<ImageView android:id="@+id/audio_progress_view" android:layout_width="match_parent" android:layout_height="32dp" android:background="@drawable/audio_progress_drawable"/>代码里获取ClipDrawable,通过设置
level来更新播放进度(level范围是0-10000,对应0%-100%):val progressView = findViewById<ImageView>(R.id.audio_progress_view) val clipDrawable = (progressView.background as LayerDrawable).getDrawable(1) as ClipDrawable // 比如播放到30%,设置level为3000 clipDrawable.level = (progress * 10000).toInt()
方案二:自定义View(更灵活,适合复杂需求)
如果需要更个性化的效果(比如渐变填充、动态波形、圆角细节调整),自定义View是更好的选择:
class AudioProgressView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) { private val bgPaint = Paint().apply { color = Color.parseColor("#E0E0E0") isAntiAlias = true style = Paint.Style.FILL } private val progressPaint = Paint().apply { color = Color.parseColor("#2196F3") isAntiAlias = true style = Paint.Style.FILL } private var progress = 0f // 0-1的进度值 private val radius = 16.dpToPx(context).toFloat() override fun onDraw(canvas: Canvas) { super.onDraw(canvas) // 绘制灰色背景 canvas.drawRoundRect(0f, 0f, width.toFloat(), height.toFloat(), radius, radius, bgPaint) // 绘制蓝色进度部分 val progressWidth = width * progress canvas.drawRoundRect(0f, 0f, progressWidth, height.toFloat(), radius, radius, progressPaint) } fun setProgress(progress: Float) { this.progress = progress.coerceIn(0f, 1f) // 限制在0-1之间 invalidate() // 触发重绘 } private fun Int.dpToPx(context: Context): Int { return (this * context.resources.displayMetrics.density).toInt() } }
然后在布局里直接使用:
<com.yourpackage.AudioProgressView android:id="@+id/custom_audio_progress" android:layout_width="match_parent" android:layout_height="32dp"/>
代码里更新进度就调用custom_audio_progress.setProgress(0.3f)就行。
关于你最初的FrameLayout思路
其实用FrameLayout叠加两个View也能实现:灰色View当背景,蓝色View放在上面,通过设置蓝色View的layout_width或者scaleX来控制显示宽度。但这种方式在处理圆角时容易出现边缘错位,而且频繁更新宽度可能不如前两种方案高效,所以更推荐上面的两种方法哦~
内容的提问来源于stack exchange,提问作者Maksim Dmitriev
相关产品推荐
相关产品推荐

