42

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?

CDrosos
  • 2,418
  • 4
  • 26
  • 49

9 Answers9

66

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));
            }
        }
    }
Lavekush Agrawal
  • 6,040
  • 7
  • 52
  • 85
Arthur Attout
  • 2,701
  • 2
  • 26
  • 49
  • 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"); – CDrosos Apr 12 '17 at 13:12
  • 1
    This works for me `drawable.setColorFilter(new PorterDuffColorFilter(resColorBlack, PorterDuff.Mode.SRC_IN));` – Jiyeh May 09 '17 at 09:15
  • 2
    For anyone looking to do this in Java: `yourTextView.getCompoundDrawables()[0].setTint(getResources().getColor(R.color.red));` – Smitty-Werben-Jager-Manjenson Jan 25 '19 at 18:55
44

I am using this in kotlin:

tv.getCompoundDrawables()[0].setTint(//color)
Giedrius Šlikas
  • 1,073
  • 12
  • 12
36

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));
        }
    }
}
  • 2
    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. – jayearn Mar 12 '20 at 14:07
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.

Yuri Misyac
  • 4,364
  • 2
  • 16
  • 32
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" />
pilladooo
  • 713
  • 6
  • 10
10

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)
Algar
  • 5,734
  • 3
  • 34
  • 51
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

Krishna Sony
  • 1,286
  • 13
  • 27
4

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.

Devendra Vaja
  • 3,836
  • 2
  • 19
  • 14
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))

}
David Buck
  • 3,752
  • 35
  • 31
  • 35
TOUSIF
  • 285
  • 5
  • 4
  • 2
    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._ – Nolan Amy Jun 30 '21 at 03:21