Android TextView DrawableTint on pre v23 devices
Asked Answered
W

4

19

Is there any way we can tint the Drawable used in the TextView? DrawableTint works only on API level 23 and above.

Currently I'm using a Vertical Linear Layout to achieve my requirement.

<LinearLayout style="@style/ChoiceIllustratorIconTextContainerStyle">

  <ImageView
    style="@style/ChoiceIllustratorImageStyle"
    android:contentDescription="@string/cd_university"
    android:src="@drawable/ic_account_balance_white_24dp" />

  <TextView
    style="@style/ChoiceIllustratorTextStyle"
    android:text="@string/ci_text_university" />

</LinearLayout>

And it looks like,enter image description here

Android studio is suggesting me to use Compound Drawble with TextView to achieve this. And I'm able to achieve it, but I cannot find a way to Tint the drawable.

<TextView
   style="@style/ChoiceIllustratorTextStyle"
   android:drawablePadding="4dp"
   android:drawableTop="@drawable/ic_account_balance_white_24dp"
   android:text="@string/ci_text_university" />
Watercourse answered 11/1, 2017 at 10:19 Comment(3)
Can this help: #29155963Greathouse
I checked that, for my case its not helpful. ThanksWatercourse
Does this answer your question? Android Button Drawable TintOckeghem
L
35

AndroidX appcompat library supports tinting in TextView since version 1.1.0-alpha03 [ref].

Add dependencies to appcompat library

dependencies {
  implementation "androidx.appcompat:appcompat:1.1.0"
}

Then drawable in TextView can be tinted from XML like this

<TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  app:drawableStartCompat="@drawable/ic_plus"
  app:drawableTint="@color/red" />

Don't forget to include

xmlns:app="http://schemas.android.com/apk/res-auto"

and to extend your Activity from AppCompatActivity.

Lowder answered 12/9, 2019 at 4:25 Comment(1)
They should add this to the ctrl+space shortcut thingyTributary
R
24

The programmatic way to do this is

       Drawable[] drawables = textView.getCompoundDrawables();
       if (drawables[0] != null) {  // left drawable
           drawables[0].setColorFilter(color, Mode.MULTIPLY);
       }

This works for all API levels.

This is your best option for pre-Marshmallow devices.

Regeniaregensburg answered 11/1, 2017 at 20:53 Comment(5)
And if you need to use a different color on another screen or for different view states, I believe you would want to mutate() the drawable before call setColorFilter.Catalepsy
PorterDuff.Mode.MULTIPLY does not work for me. Instead, PorterDuff.Mode.SRC_ATOP works for me. Does PorterDuff.Mode.MULTIPLY for you?Lord
SRC_ATOP was what the OP settled on, so it's not surprising that it works for you too. Can't remember exactly, but I think I might have been using a drawable with all-white pixels, so that MULTIPLY and SRC_ATOP would look pretty much the same. The OP's method of using the compatibility classes is a better option as well.Regeniaregensburg
for reference : drawable[0] left, drawable[1] top, drawable[2] right, drawable[3] bottom . Thanks this works.Fro
Thanks this worked. Also note to use getCompoundDrawablesRelative for Start/Top/End/BottomFruitarian
W
15

This answer is based on @kris larson suggestion.

I use the following methods and it is working fine on all devices.

setTintedCompoundDrawable a custom method that takes the TextView to which you would want to set the compound drawable, a drawable res id & and the res id of your color choice.

private void setTintedCompoundDrawable(TextView textView, int drawableRes, int tintRes) {
    textView.setCompoundDrawablesWithIntrinsicBounds(
            null,  // Left
            Utils.tintDrawable(ContextCompat.getDrawable(getContext(), drawableRes),
                    ContextCompat.getColor(getContext(), tintRes)), // Top
            null, // Right
            null); //Bottom
    // if you need any space between the icon and text.
    textView.setCompoundDrawablePadding(12);
}

Tint tintDrawable method goes like this:

public static Drawable tintDrawable(Drawable drawable, int tint) {
    drawable = DrawableCompat.wrap(drawable);
    DrawableCompat.setTint(drawable, tint);
    DrawableCompat.setTintMode(drawable, PorterDuff.Mode.SRC_ATOP);

    return drawable;
}
Watercourse answered 6/9, 2017 at 13:37 Comment(1)
call mutate() on the drawable loaded from resource id to get a separate drawable if you use the drawable resource somewhere else in the app with a different tint.Meyers
A
9

You could use TextViewCompat class for this case:

TextViewCompat.setCompoundDrawableTintList(TextView, ColorStateList)
Airspeed answered 18/7, 2020 at 12:6 Comment(4)
this won't work. This will always take effect when running on API v24 or newerPyrenees
@YouQi Compat class is used, it means supports all the versionsAirspeed
You may want to read the doc of the function: This will always take effect when running on API v24 or newer. When running on platforms previous to API v24, it will only take effect if textView implements the TintableCompoundDrawablesView interface. ```. given the context of the question is below 24, your answer is not good enough as you didn't address the full caveatPyrenees
Works great with MaterialTextView on API 21Denton

© 2022 - 2024 — McMap. All rights reserved.