在 Android 中自訂水平進度條(ProgressBar)顏色,雖然常透過 XML layer-list 定義,但若需在執行期動態改變顏色(如依據下載狀態、主題切換),則必須使用純 Java/Kotlin 程式碼建構 LayerDrawable。
進度條由三層疊加組成:
@android:id/background:背景軌道@android:id/secondaryProgress:次要進度(如緩衝進度)@android:id/progress:主要進度<layer-list xmlns:android="https://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<corners android:radius="5dp" />
<gradient android:startColor="#ff9d9e9d" android:centerColor="#ff5a5d5a" android:endColor="#ff747674" android:angle="270" />
</shape>
</item>
<item android:id="@android:id/secondaryProgress">
<clip>
<shape>
<corners android:radius="5dp" />
<gradient android:startColor="#80ffd300" android:centerColor="#80ffb600" android:endColor="#a0ffcb00" android:angle="270" />
</shape>
</clip>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="5dp" />
<gradient android:startColor="@color/progress_start" android:endColor="@color/progress_end" android:angle="270" />
</shape>
</clip>
</item>
</layer-list>
public LayerDrawable createProgressDrawable(int bgStart, int bgCenter, int bgEnd,
int secStart, int secCenter, int secEnd,
int progStart, int progEnd) {
// 1. 背景層
ShapeDrawable bgShape = new ShapeDrawable(new RoundRectShape(new float[]{5,5,5,5,5,5,5,5}, null, null));
bgShape.getPaint().setShader(new LinearGradient(0, 0, 0, 100,
new int[]{bgStart, bgCenter, bgEnd}, null, Shader.TileMode.CLAMP));
// 2. 次要進度層
ShapeDrawable secShape = new ShapeDrawable(new RoundRectShape(new float[]{5,5,5,5,5,5,5,5}, null, null));
secShape.getPaint().setShader(new LinearGradient(0, 0, 0, 100,
new int[]{secStart, secCenter, secEnd}, null, Shader.TileMode.CLAMP));
ClipDrawable secondary = new ClipDrawable(secShape, Gravity.LEFT, ClipDrawable.HORIZONTAL);
// 3. 主要進度層
ShapeDrawable progShape = new ShapeDrawable(new RoundRectShape(new float[]{5,5,5,5,5,5,5,5}, null, null));
progShape.getPaint().setShader(new LinearGradient(0, 0, 0, 100,
new int[]{progStart, progEnd}, null, Shader.TileMode.CLAMP));
ClipDrawable progress = new ClipDrawable(progShape, Gravity.LEFT, ClipDrawable.HORIZONTAL);
// 4. 組合 LayerDrawable
Drawable[] layers = {bgShape, secondary, progress};
LayerDrawable layerDrawable = new LayerDrawable(layers);
layerDrawable.setId(0, android.R.id.background);
layerDrawable.setId(1, android.R.id.secondaryProgress);
layerDrawable.setId(2, android.R.id.progress);
return layerDrawable;
}
ProgressBar progressBar = findViewById(R.id.progressBar);
LayerDrawable drawable = createProgressDrawable(
0xFF9D9E9D, 0xFF5A5D5A, 0xFF747674, // 背景漸層
0x80FFD300, 0x80FFB600, 0xA0FFCB00, // 次要進度漸層
0xFF00FF00, 0xFF008800 // 主要進度漸層
);
progressBar.setProgressDrawable(drawable);
setId() 必須使用 android.R.id.background、secondaryProgress、progress,否則 ProgressBar 無法正確對應層級。Gravity.LEFT 與 ClipDrawable.HORIZONTAL。LayerDrawable 實例,避免重複建構物件。