85

Is it possible to make drawable tinting work for api < 21?

<bitmap
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/ic_calendar"
    android:tint="@color/primary" />

Works just fine but only for devices with API21. Any workaround for lower api devices or AppCompat support? Can't find anything.

MaTTo
  • 2,326
  • 5
  • 20
  • 24

10 Answers10

111

Use the AppCompatImageView like so:

<android.support.v7.widget.AppCompatImageView
        android:id="@+id/my_appcompat_imageview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/my_image"
        android:tint="#636363"
    />

Make sure you have the latest appcompat-v7 in your app's build.gradle.

Example: compile 'com.android.support:appcompat-v7:25.0.0' in your app's build.gradle.

Sakiboy
  • 7,252
  • 7
  • 52
  • 69
  • 67
    From `AppCompatImageView` docs: `This will automatically be used when you use ImageView in your layouts. You should only need to manually use this class when writing custom views.` http://developer.android.com/reference/android/support/v7/widget/AppCompatImageView.html So, using the normal `ImageView` in the layout should work just fine. – Nimrod Dayan Jul 14 '16 at 12:34
  • 1
    As @NimrodDayan mentioned above, this shouldn't be necessary. I am getting reports of android:tint not working on a Samsung A5 and Moto G, however (using appcompat-v7:23.4.0), so it's possible ImageViews aren't being replaced properly on some devices. – Stephen Kidson Jul 15 '16 at 01:32
  • @StephenKidson, I'm using the same version of appcompat and also bumped into the same issue on an unknown brand device. Did you manage to solve this? I wonder if there's bug reported about this... – Nimrod Dayan Jul 15 '16 at 08:37
  • @NimrodDayan worked around it by making a separate drawable XML for the color I was tinting to - not ideal but pretty much the only way to ensure the issue was resolved without getting ahold of each affected device. – Stephen Kidson Jul 18 '16 at 20:37
  • 4
    This did not work on emulator Android 4.0 using appcompat-v7:25.1.0. – Peterdk Jan 29 '17 at 19:04
  • 4
    AppCompatImageView cannot be used inside a Widget. Use setColorFilter on the ImageView. – Massimo Feb 01 '17 at 14:58
46

You can achieve that using source code. Previously tinting was not supported by DrawableCompat. Starting from support library 22.1 you can do that, but you need do it in this way:

Drawable normalDrawable = getResources().getDrawable(R.drawable.drawable_to_tint);
Drawable wrapDrawable = DrawableCompat.wrap(normalDrawable);
DrawableCompat.setTint(wrapDrawable, getResources().getColor(R.color.colorPrimaryLight));
Simon K. Gerges
  • 3,097
  • 36
  • 34
  • 18
    If you need to support tinting on < 21 APIs, then you probably want to use `ContextCompat.getColor()` instead of `getResources().getColor()`. – Sevastyan Savanyuk Sep 07 '17 at 07:33
22

Couldn't you simply use an ImageView to display your Drawable? android:tint works fine on older API levels.

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_calendar"
    android:tint="@color/primary"
    />
Jonik
  • 80,077
  • 70
  • 264
  • 372
  • 2
    I am using ImageView - to display icon in it. Those icons are part of elements in my navigation drawer. And selected item in navigation drawer has different color, so I created each icon tinted and also selector for each icon. And I am using that selector for my icon. Selector: ` ` – MaTTo Mar 19 '15 at 21:58
  • @Orochi Take a look at my answer as it come directly from Google's blogs. It mainly only works on Android 5.0+ but may work on some widgets for devices running pre-Android 5.0. – Jared Burrows Mar 19 '15 at 22:00
  • @Orochi You are going to have to make custom views to "emulate" the same effect. – Jared Burrows Mar 19 '15 at 22:00
  • @Orochi: Ah, sorry, misunderstood the context. – Jonik Mar 19 '15 at 22:01
  • So, should I just color the icon myself and put it in my drawable folder? – MaTTo Mar 19 '15 at 22:11
  • 1
    You could use an image view, make the icon as white as possible, and make it any color you want with iv.setColorFilter(yourColor, Mode.Multiply); Make sure you import android.graphics.PorterDuff.Mode – jb15613 Mar 19 '15 at 22:37
  • 3
    Same problem here. Sadly the tint with selector does not work with api < 21 – Luccas Mar 21 '16 at 20:56
17

A similar question has been asked before here: https://stackoverflow.com/a/26533340/950427

Android Drawable Tinting is supported in Android 5.0+ (API 21+) only. (It does say "At the moment this is limited to coloring the action bar and some widgets.").

Theming

...

When you set these attributes, AppCompat automatically propagates their values to the framework attributes on API 21+. This automatically colors the status bar and Overview (Recents) task entry.

On older platforms, AppCompat emulates the color theming where possible. At the moment this is limited to coloring the action bar and some widgets.

And

Widget tinting

When running on devices with Android 5.0, all of the widgets are tinted using the color theme attributes we just talked about. There are two main features which allow this on Lollipop: drawable tinting, and referencing theme attributes (of the form ?attr/foo) in drawables.

AppCompat provides similar behaviour on earlier versions of Android for a subset of UI widgets:

Everything provided by AppCompat’s toolbar (action modes, etc) EditText Spinner CheckBox RadioButton Switch (use the new android.support.v7.widget.SwitchCompat) CheckedTextView You don’t need to do anything special to make these work, just use these controls in your layouts as usual and AppCompat will do the rest (with some caveats; see the FAQ below).

Sources:

http://android-developers.blogspot.com/2014/10/appcompat-v21-material-design-for-pre.html

https://chris.banes.me/2014/10/17/appcompat-v21/

Community
  • 1
  • 1
Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
13

Now AppCompatImageView,AppCompatButton will replace the ImageView,Button to support tint on devices with lower API. Check link for more details AppCompatImageView,AppCompatButton

Ankit Singh
  • 149
  • 1
  • 4
6

For tinting images you could use imageView.setColorFilter(int color). This works from API 8 and worked for tinting my black image to a color I wanted. This can replace setImageTintList() but just using android:tint should also work.

Peterdk
  • 15,625
  • 20
  • 101
  • 140
5

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

and after you can replace every android:tint with app:tint. This fix the issue for me.

seinta
  • 115
  • 1
  • 6
4

I'm a little late but here's how to do it.

val textInput = EditText(context)

val drawable = ContextCompat.getDrawable(context, R.drawable.your_drawable)
drawable?.let {
    myDrawable -> DrawableCompat.setTint(myDrawable, ContextCompat.getColor(context, R.color.your_color))
    textInput.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, myDrawable, null)
}
Teocci
  • 7,189
  • 1
  • 50
  • 48
Crazy
  • 576
  • 6
  • 5
1

This will do as you want, and should work on all Android versions of the support library:

Kotlin:

    @JvmStatic
    fun getTintedDrawable(inputDrawable: Drawable, @ColorInt color: Int): Drawable {
        val wrapDrawable = DrawableCompat.wrap(inputDrawable.mutate())
        DrawableCompat.setTint(wrapDrawable, color)
        DrawableCompat.setTintMode(wrapDrawable, Mode.SRC_IN)
        return wrapDrawable
    }

Java:

    public static Drawable getTintedDrawable(Drawable inputDrawable, @ColorInt int color) {
        Drawable wrapDrawable = DrawableCompat.wrap(inputDrawable.mutate());
        DrawableCompat.setTint(wrapDrawable, color);
        DrawableCompat.setTintMode(wrapDrawable, PorterDuff.Mode.SRC_IN);
        return wrapDrawable;
    }
Chester Fung
  • 182
  • 1
  • 10
android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • I like this answer. `mutate()` and `wrap` is required for SDK < 21. For SDK >=21, the functions will just return the `inputDrawable` so there is no cost to use these functions. Besides, after wrapped, actually `setTint` and `setTintMode` can be directly called from `wrapDrawable` without using `DrawableCompat`'s static method. – Chester Fung May 06 '23 at 10:27
  • @ChesterFung In case the SDK>=21, what should it look like (please check before answering) ? – android developer May 06 '23 at 11:36
1

If anyone want create new drawable (tin1,tint2..) try this

<?xml version="1.0" encoding="utf-8"?>
<bitmap
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:src="@drawable/your_image"
  android:tint="@color/tint_color">
   </bitmap>
Ranjithkumar
  • 16,071
  • 12
  • 120
  • 159