Android - Tinting ProgressBar on pre-Lollipop devices
Asked Answered
A

6

20

My app's minimum API-level is 19 (KitKat), and contains a layout with a horizontal ProgressBar. I'm using android:progressTint attribute to tint the bar to a custom color. It works pretty well on Lollipop (API 21) and above, but below (for example on API 19) it doesn't; it shows up in a different color. The reason is that this attribute

is only used in API level 21 and higher

as Android Studio states.

So I'm wondering what can be a good alternative for tinting the ProgressBar on pre-Lollipop devices, too. Can it be made inside the layout file with XML? Or should this be done on a different way?


EDIT #1: My ProgressBar is used to show concrete values in percents, not for indicating that my layout is loading. I want to make this clear because after trying what Kuldeep Kulkarni wrote below, my bar looked like a material loading indicator (of course on the Lollipop device, not any visible result on KitKat device).

Astyanax answered 6/4, 2017 at 9:47 Comment(1)
progressTint is not working for me on Lollipop anyone knows the reason whyMolten
A
8

Thanks for the suggestions from everyone! :)

The solution which works for me is to create a custom drawable XML file with the <layer-list> root element. There, I'm defining two layer items with the native Android IDs @android:id/background and @android:id/progress. After this, I can define the shapes and color resources I would like to use. This solution is similar to a more popular answer on this SO question.


Content of my res/drawable/progressbar.xml file:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@android:id/background">

        <shape>

            <corners android:radius="2dip" /> <!--optional-->

            <gradient
                android:angle="270"
                android:endColor="@color/gray"
                android:startColor="@color/gray" />

        </shape>

    </item>

    <item android:id="@android:id/progress">

        <clip>

            <shape>

                <corners android:radius="2dip" /> <!--optional-->

                <gradient
                    android:angle="270"
                    android:endColor="@color/blue"
                    android:startColor="@color/blue" />

            </shape>

        </clip>

    </item>

</layer-list>

Defined as progressDrawable for my ProgressBar in the layout XML file:

<ProgressBar
        android:id="@+id/progress_bar"
        android:layout_width="0dp"
        android:layout_height="@dimen/progress_bar_height"
        android:progressDrawable="@drawable/progressbar" />

I didn't have a chance to test it below API 19, but on this level and above it works perfectly.

Astyanax answered 11/9, 2017 at 14:8 Comment(0)
H
32

You can wrap with ProgressBar indeterminateDrawable method for pre-Lollipop.

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {

     Drawable drawableProgress = DrawableCompat.wrap(progressBar.getIndeterminateDrawable());
     DrawableCompat.setTint(drawableProgress, ContextCompat.getColor(getContext(), android.R.color.holo_green_light));
     progressBar.setIndeterminateDrawable(DrawableCompat.unwrap(drawableProgress));

} else {
    progressBar.getIndeterminateDrawable().setColorFilter(ContextCompat.getColor(getContext(), android.R.color.holo_green_light), PorterDuff.Mode.SRC_IN);
}
Husbandman answered 6/4, 2017 at 10:23 Comment(2)
I've tried to use it, the code also runs, but no visible results... also see the question's edit.Astyanax
You need setProgressDrawableRevanche
A
11
progress.getProgressDrawable().setColorFilter(color, PorterDuff.Mode.SRC_IN);
Afterwards answered 2/6, 2018 at 7:39 Comment(3)
While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value.Petersen
This solution worked for me better than the currently highest rated one.Tayler
This is deprecated nowGastroenterology
A
8

Thanks for the suggestions from everyone! :)

The solution which works for me is to create a custom drawable XML file with the <layer-list> root element. There, I'm defining two layer items with the native Android IDs @android:id/background and @android:id/progress. After this, I can define the shapes and color resources I would like to use. This solution is similar to a more popular answer on this SO question.


Content of my res/drawable/progressbar.xml file:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@android:id/background">

        <shape>

            <corners android:radius="2dip" /> <!--optional-->

            <gradient
                android:angle="270"
                android:endColor="@color/gray"
                android:startColor="@color/gray" />

        </shape>

    </item>

    <item android:id="@android:id/progress">

        <clip>

            <shape>

                <corners android:radius="2dip" /> <!--optional-->

                <gradient
                    android:angle="270"
                    android:endColor="@color/blue"
                    android:startColor="@color/blue" />

            </shape>

        </clip>

    </item>

</layer-list>

Defined as progressDrawable for my ProgressBar in the layout XML file:

<ProgressBar
        android:id="@+id/progress_bar"
        android:layout_width="0dp"
        android:layout_height="@dimen/progress_bar_height"
        android:progressDrawable="@drawable/progressbar" />

I didn't have a chance to test it below API 19, but on this level and above it works perfectly.

Astyanax answered 11/9, 2017 at 14:8 Comment(0)
W
7

This works for me

<ProgressBar
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:theme="@style/progressBarBlue" />

Then in your style.xml define progressBarBlue

<style name="progressBarWhite" parent="@style/Theme.AppCompat">
   <item name="colorAccent">@color/blue</item>
</style>
Winfrid answered 3/7, 2019 at 10:20 Comment(0)
T
0

If you want to do it programmatically, try this

public static void setSeekbarTint(SeekBar seekbar, int color) {
        PorterDuff.Mode porterDuffMode = PorterDuff.Mode.SRC_IN;
        if (seekbar.getIndeterminateDrawable() != null)
            seekbar.getIndeterminateDrawable().setColorFilter(color, porterDuffMode);

        if (seekbar.getProgressDrawable() != null &&
                seekbar.getProgressDrawable() instanceof LayerDrawable) {
            LayerDrawable layerDrawable = (LayerDrawable) seekbar.getProgressDrawable();
            GradientDrawable gradientDrawable = (GradientDrawable) layerDrawable.findDrawableByLayerId(android.R.id.background);

            layerDrawable.setColorFilter(color, porterDuffMode);
            seekbar.setProgressDrawable(layerDrawable);
            gradientDrawable.setColorFilter(Color.WHITE, porterDuffMode);
        } else if (seekbar.getProgressDrawable() != null &&
                seekbar.getProgressDrawable() instanceof ClipDrawable) {
            ClipDrawable clipDrawable = (ClipDrawable) seekbar.getProgressDrawable();
            clipDrawable.setColorFilter(color, porterDuffMode);
            seekbar.setProgressDrawable(clipDrawable);
        }
}
Triadelphous answered 30/8, 2019 at 15:1 Comment(0)
O
-4

I hope this will help you. Try this:

<ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminate="true"
        android:indeterminateTint="#F00"
        android:indeterminateTintMode="src_in" />
Oberheim answered 6/4, 2017 at 10:6 Comment(2)
Sorry, it doesn't work as I would like to - the indeterminateTint attribute uses app's primary color, which differs from the color I want to use; it works also on API 21 and above.Astyanax
This is not pre-Lollipop compatible as it is asked for.Ideal

© 2022 - 2024 — McMap. All rights reserved.