Setting the Color of a TextView Drawable
Asked Answered
C

10

50

Im trying to change the color of a TextView Drawable in Xamarin.

In Java you can do it like this:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    TextView txt = (TextView) findViewById(R.id.my_textview);
    setTextViewDrawableColor(txt, R.color.my_color);
}

private void setTextViewDrawableColor(TextView textView, int color) {
    for (Drawable drawable : textView.getCompoundDrawables()) {
        if (drawable != null) {
            drawable.setColorFilter(new PorterDuffColorFilter(getColor(color), PorterDuff.Mode.SRC_IN));
        }
    }
}

How i can do something like this in Xamarin.Android?

Carinacarinate answered 12/4, 2017 at 12:25 Comment(0)
D
71

Try below solution

private void setTextViewDrawableColor(TextView textView, int color) {
        for (Drawable drawable : textView.getCompoundDrawables()) {
            if (drawable != null) {
                drawable.setColorFilter(new PorterDuffColorFilter(ContextCompat.getColor(textView.getContext(), color), PorterDuff.Mode.SRC_IN));
            }
        }
    }
Ditzel answered 12/4, 2017 at 12:37 Comment(3)
those also might help if someone want to convert resource color to android color: new Android.Graphics.Color (ContextCompat.GetColor (this, Resource.Color.bb_orange) and Color.ParseColor("#000000");Carinacarinate
This works for me drawable.setColorFilter(new PorterDuffColorFilter(resColorBlack, PorterDuff.Mode.SRC_IN));Skiing
For anyone looking to do this in Java: yourTextView.getCompoundDrawables()[0].setTint(getResources().getColor(R.color.red));Shamefaced
F
49

I am using this in kotlin:

tv.getCompoundDrawables()[0].setTint(//color)
Figured answered 28/6, 2019 at 11:18 Comment(4)
I would do: tv.getCompoundDrawables()[0]?.setTint(//color)Smelter
should be the answer!Bernal
This allows us to set the tint for API levels below M. Thank you!Termless
Simple and you can apply foreach to make all drawbles the same if you use them all.Cyrilla
S
38

Please, notice that if you set drawables in your layout file via android:drawableStart or android:drawableEnd instead of android:drawableLeft and android:drawableRight respectively you should use TextView.getCompoundDrawablesRelative(). Otherwise you can get empty array of drawables.

private void setTextViewDrawableColor(TextView textView, int color) {
    for (Drawable drawable : textView.getCompoundDrawablesRelative()) {
        if (drawable != null) {
            drawable.setColorFilter(new PorterDuffColorFilter(ContextCompat.getColor(textView.getContext(), color), PorterDuff.Mode.SRC_IN));
        }
    }
}
Sickroom answered 4/3, 2020 at 12:59 Comment(1)
Thanks for this! Very interesting, I was doing this tinting in a RecyclerView and it wasn't reliable. With compoundDrawablesRelative it seems to be fine.Lobotomy
B
19
// index of drawable
val left = 0
val start = left
val top = 1
val right = 2
val end = right
val bottm = 3

// color int
val color = Color.RED

// apply tint for target drawable
textView.compoundDrawables.getOrNull(left)?.setTint(color)

// apply tint for all drawables
textView.compoundDrawables?.forEach { it?.setTint(color) }

NOTE!

if in XML layout you use android:stratDrawable or android:endDrawable you have to work with textView.compoundDrawablesRelative array, textView.compoundDrawables contains drawables when they have been added with android:leftDrawable or android:rightDrawable attributes.

Brutal answered 19/5, 2020 at 14:24 Comment(1)
If compoundDrawables are null try compoundDrawablesRelativeCubage
U
14

There's built in support for this through TextViewCompat.setCompoundDrawableTintList(textView, colors)

val color = ContextCompat.getColor(context, R.color.foo)
val colorList = ColorStateList.valueOf(color)
TextViewCompat.setCompoundDrawableTintList(textView, colorList)
Ungava answered 18/1, 2022 at 10:15 Comment(0)
H
11

I solve this problem adding in xml definition this line:

android:drawableTint="@color/red"

A complete example:

        <TextView
            android:id="@+id/tv_element"
            android:layout_width="wrap_content"
            android:layout_height="20dp"
            android:layout_alignParentEnd="true"
            android:drawableStart="@drawable/ic_icon"
            android:drawableTint="@color/color"
            android:visibility="visible" />
Hanahanae answered 25/3, 2020 at 11:56 Comment(0)
B
5

I faced the problem where I am changing the color of the compound drawable and except one rest of all the colors are constant. Confusing for me.!!!

the solution that worked for me is

// Pass through the each drawable and update the tint if drawable is set.
textView.compoundDrawables.filterNotNull().forEach { drawable ->
        drawable.mutate()
        drawable.setTint(drawableColor)
    }

Without the mutate(), the things were working partially. I got the more details here Drawable Mutations .

For the interest of the reader, I am providing a quick summery below.

Android Drawables are the drawing containers. Such as BitmapDrawable is used to display the images, ShapeDrawable is used to display the shapes and gradients.

Drawables are used extensively in the Android ecosystem thus they are optimized. So when views are created the different instances are spawned but the drawables associated with the view share the common state, called "Constant state".

For example, if a drawable is a BitmapDrawable then the same bitmap is used with the all the corresponding copies or views.

Advantage: It simply saves huge amount of memory.

Problem: As the same drawable is shared across the various views. Any change in the state of the drawable such as alpha, transformation etc. will impact all the places where it is used.

Solution: The mutate() method when called on a drawable, the constant state of the drawable is duplicated to allow you to change any property without affecting other drawables. Note: Bitmap is still shared.

Banner answered 24/8, 2022 at 19:14 Comment(0)
L
4

For Kotlin. Use the below extension for the TextView drawable. It supports below and above API level of 23.

    private fun TextView.setTextViewDrawableColor(color: Int) {
        for (drawable in this.compoundDrawablesRelative) {
            drawable?.mutate()
            drawable?.colorFilter = PorterDuffColorFilter(
                color, PorterDuff.Mode.SRC_IN
            )
        }
    }

Note: You can also use this function in the RecyclerView item as well, It will not override the same color for each item

Luo answered 30/4, 2021 at 13:56 Comment(2)
Not working....Zephan
use it instead tv.getCompoundDrawables()[0]?.setTint(//color)Bernal
L
3

If you want to change the tint color of the drawable of any view (tested on API 29) :

private fun setTintColor(textView: TextView, color: Int) {

    DrawableCompat.setTint(DrawableCompat.wrap(textView.background).mutate(), 
    ContextCompat.getColor(this, color))

}
Limiting answered 25/9, 2020 at 5:9 Comment(1)
Why the mutate() call is important: By default, all drawables instances loaded from the same resource share a common state; if you modify the state of one instance, all the other instances will receive the same modification.Sitnik
B
1

I create extension like this

fun TextView.setDrawableTintExt(color: Any) {
    
    when (color) {
        is String -> {
            for (drawable in this.compoundDrawables) {
                if (drawable != null) {
                    drawable.colorFilter =
                        PorterDuffColorFilter(
                            getHexColorExt(color),
                            PorterDuff.Mode.SRC_IN
                        )
                }
            }
        }
        
        is Int -> {
            for (drawable in this.compoundDrawables) {
                if (drawable != null) {
                    drawable.colorFilter =
                        PorterDuffColorFilter(
                            ContextCompat.getColor(this.context, color),
                            PorterDuff.Mode.SRC_IN
                        )
                }
            }
        }
    }
    
}
Battle answered 15/11, 2023 at 7:0 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.