Changing the Color of the Custom Progress Bar Programmatically - Solved

77 Views Asked by At

I'm trying to change the color of the customized ProgressBar dynamically with Java.

This is the implementation of the ProgressBar on the main layout:

[activity_main.xml]

    <ProgressBar
    android:id="@+id/progressBar"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="match_parent"
    android:layout_height="8dp"
    android:layout_marginTop="8dp"
    android:layout_marginBottom="8dp"
    android:progressDrawable="@drawable/custom_progress"
    android:background="@drawable/custom_progress_bar"
    android:max="100"
    android:progress="80" />

I have created two seperate drawables to customize the progress bar as follows:

[custom_progress_bar.xml & custom_progress.xml]

<!-- custom_progress_bar.xml -->

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background">
        <shape android:shape="rectangle">
            <corners android:radius="8dp"/>
            <solid android:color="@color/white"/>
        </shape>
    </item>
</layer-list>
<!-- custom_progress.xml -->

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/progress_solid">
        <clip>
            <shape android:shape="rectangle">
                <corners android:radius="8dp"/>
                <solid android:color="@color/progress"/>
            </shape>
        </clip>
    </item>
</layer-list>

Here is the Java code that is supposed to change the progress bar from green (@color/progress) to red:

[MainActivity.java]

LayerDrawable layerDrawable = (LayerDrawable) ContextCompat.getDrawable(this, R.drawable.custom_progress);
ClipDrawable progressSolid = (ClipDrawable) layerDrawable.findDrawableByLayerId(R.id.progress_solid);
GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(Color.RED);
progressSolid.setDrawable(gradientDrawable);
progressBar.invalidate();

This is the theme, (I've set out both themes to be exactly the same):

[themes.xml & themes.xml (night)]

<resources xmlns:tools="http://schemas.android.com/tools">
    <!-- Base application theme. -->
    <style name="Base.Theme.CountdownCalender" parent="Theme.Material3.DayNight.NoActionBar">
        <!-- Customizing the light theme here. -->
        <item name="colorPrimaryVariant">@color/black</item>
        <item name="colorPrimaryDark">@color/black</item>
        <item name="colorPrimary">@color/progress</item>
        <item name="colorOnPrimary">@color/white</item>
        <item name="colorSurface">@color/white</item>
    </style>

    <style name="Theme.CountdownCalender" parent="Base.Theme.CountdownCalender" />

    <style name="CalenderViewDateCustomText">
        <item name="colorControlActivated">@drawable/selected_day</item>
        <item name="android:textColor">@color/white</item>
        <item name="android:weekDayTextAppearance">@color/accent</item>
    </style>
</resources>

The unwanted result: unwanted result

This is not the result I want. I want it to change to red as the Java code shows. What am I missing? My co-pilot chatbot is not helping.. I'd really appreciate the help. Thank you in advance.

SOLUTION: Turns out I just needed these few lines:

LayerDrawable layerDrawable = (LayerDrawable) progressBar.getProgressDrawable();
Drawable progressFill = layerDrawable.getDrawable(1);
progressFill.setColorFilter(Color.RED, PorterDuff.Mode.SRC_IN);

and replace the previous code. I'm yet to research what the last line is exactly, but it works as shown below: desired output

2

There are 2 best solutions below

1
Lino On

Let's suppose progress is a variable holding a reference to your progressbar then you can use the following Java code to change the progress color programmatically:

LayerDrawable drawable = (LayerDrawable) progress.getProgressDrawable();
Drawable progressLayer = drawable.findDrawableByLayerId(android.R.id.progress);
setTintList(progressLayer.mutate(), context.getResources().getColorStateList(R.color.white, context.getTheme()))

equivalent in Kotlin:

val drawable = progress.progressDrawable as LayerDrawable
val progressLayer = drawable.findDrawableByLayerId(android.R.id.progress)
setTintList(progressLayer.mutate(), resources.getColorStateList(R.color.white, theme))

setTintLint is a static function from DrawableCompat. The color should be a valid ColorRes resource. Hope this helps.

0
Kavyasri K On
progressBar.progressTintList = ContextCompat.getColorStateList(this, R.color.teal_700)