I am using android support library and besides limited number of widgets that are tinted with color accentColor defined in theme I would like to tint some other drawables which I use across my app.
I do this via this code:
public class ActivityTest extends AppCompatActivity {
protected void tintDrawable(int color, int drawableId) {
Drawable drawable = DrawableCompat.wrap(ContextCompat.getDrawable(this, drawableId));
DrawableCompat.setTint(drawable, color);
}
protected void tintDrawables() {
int colorPrimary = getColorFromAttributeId(this, R.attr.colorPrimary);
tintDrawable(colorPrimary, R.drawable.drawable_1);
tintDrawable(colorPrimary, R.drawable.drawable_2);
tintDrawable(colorPrimary, R.drawable.drawable_3);
tintDrawable(colorPrimary, R.drawable.drawable_4);
tintDrawable(colorPrimary, R.drawable.drawable_5);
tintDrawable(colorPrimary, R.drawable.drawable_6);
}
public static int getColorFromAttributeId(Context context, int resourceAttributeId) {
int[] attributes = new int[] { resourceAttributeId };
TypedArray typedArray = context.obtainStyledAttributes(attributes);
int color = typedArray.getColor(0, Color.TRANSPARENT);
typedArray.recycle();
return color;
}
protected void doSetPreferencedThemeOnCreateSetContentView(Bundle savedInstanceState, int layoutResourceId) {
/* Catch 22:
* This order must be used otherwise an exception is thrown or theme is not applied.
* 1. setTheme()
* 1.b tintDrawables only after the theme is known we can get the color
* 2. onCreate()
* 3. setContentView() *
* 4. setSupportActionBar() */
// Apply theme. This must be done before super.onCreate()
setTheme(R.style.Theme_Custom_Theme); // in real case theme is retrieved from preferences
tintDrawables();
super.onCreate(savedInstanceState);
setContentView(layoutResourceId);
}
#Override
public void onCreate(Bundle savedInstanceState)
{
doSetPreferencedThemeOnCreateSetContentView(savedInstanceState, R.layout.activity_test);
}
}
It looks complicated but it is easy to understand. The problem is that my drawables are tinted "randomly". Some are, and some are not and retain the color as set in original png. To make matters worse if I leave the activity and come back, the result might be different. There could be more drawables tinted correctly or less.
What I am guessing is that tinting is asynchronous and the layout gets created before tint is applied to all drawables. But this is just a guess.
This problem is annoying as my UI depends on correct tinting, White icons on white background are not much of use. Neither are black on black.
How to enforce correct tinting of drawables?
I know this is old, but I ran in to the same problem. Calling mutate() on the drawable ensures that it will not share its state with any other drawable. From the docs:
"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"
In my case, this was causing random problems with the tinting.
Related
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?
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));
}
}
}
I am using this in kotlin:
tv.getCompoundDrawables()[0].setTint(//color)
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));
}
}
}
// 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.
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" />
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)
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))
}
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
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.
In my app I have a ViewPager that holds images. When the user scrolls through the images, there is a color animation that transitions the action bar color and status bar color between the two bitmap's palette's vibrant colors. The issue I see is that while it works great, it becomes very choppy when large images are selected.
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
Palette paletteBefore = Palette.from(imagePagerAdapter.bitmap.get(position)).generate();
Palette paletteAfter = Palette.from(imagePagerAdapter.bitmap.get(position + 1)).generate();
//Using this to get the average color between the two palette colors at the current position offset.
int color = (Integer) new ArgbEvaluator().evaluate(positionOffset, paletteBefore.getVibrantColor(Color.parseColor("#2196F3")), paletteAfter.getVibrantColor(Color.parseColor("#2196F3")));
int darkColor = (Integer) new ArgbEvaluator().evaluate(positionOffset, paletteBefore.getDarkVibrantColor(Color.parseColor("#1976D2")), paletteAfter.getDarkVibrantColor(Color.parseColor("#1976D2")));
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(color));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().setStatusBarColor(darkColor);
}
}
I know that there is a built-in asynchronous method that generates the palette in a background thread, but I am unable to access the generated palette:
Palette.from(imagePagerAdapter.bitmap.get(position)).generate(new Palette.PaletteAsyncListener() {
#Override
public void onGenerated(Palette p) {
paletteBefore = p; //Variable "paletteBefore" is accessed from within class, needs to be declared final
}
});
Even if I create a global variable to hold a palette object, it always ends up being null. I have no idea how to solve this, any ideas?
As you said, this is generating them asynchronously.
You cannot guarantee that both palettes will be created at the same time just in time to generate your colors.
The time taken will depend on the size of the image.
I would move all palette generation out of onPageScrolled()
Try creating the palettes as soon as the bitmap is accessible from each of your fragment/view
That way there might be a better chance of having them by the time the user scrolls.
I'm trying to bring material text selection handles to my app. I got drawables from the SDK for middle/right/left handle (bitmaps) and text cursor (9-patch), and set:
<item name="android:textSelectHandleLeft">#drawable/text_select_handle_left_mtrl_alpha</item>
<item name="android:textSelectHandleRight">#drawable/text_select_handle_right_mtrl_alpha</item>
<item name="android:textSelectHandle">#drawable/text_select_handle_middle_mtrl_alpha</item>
<item name="android:textCursorDrawable">#drawable/text_cursor_mtrl_alpha</item>
It works as expected. However, in Lollipop these drawables are tinted with a particular color in XML using the android:tint attribute, which I can't use on API<21. So I'm trying to set a color filter at runtime.
Text cursor does not get tinted. I think this might be due to it being a 9 patch. How can a 9-patch drawable be filtered at runtime? I tried probably all of PorterDuff.Modes.
Right/left handles are black, while middle handle is white.
I.e., non of them is green as I would like. Why?
As you can see above, I set up four ImageView below my edit text, and they instead get tinted.
private void setUpTextCursors() {
Drawable left = getResources().getDrawable(R.drawable.text_select_handle_left_mtrl_alpha);
Drawable right = getResources().getDrawable(R.drawable.text_select_handle_right_mtrl_alpha);
Drawable middle = getResources().getDrawable(R.drawable.text_select_handle_middle_mtrl_alpha);
Drawable cursor = getResources().getDrawable(R.drawable.text_cursor_mtrl_alpha);
ColorFilter cf = new PorterDuffColorFilter(mGreenColor, PorterDuff.Mode.SRC_IN);
/**
* tint my ImageViews, but no effect on edit text handles
*/
left.setColorFilter(cf);
right.setColorFilter(cf);
middle.setColorFilter(cf);
/**
* no effect whatsoever
*/
cursor.setColorFilter(cf);
}
Looks like here we have both a 9-patch tinting issue - since filter fails even on test ImageViews - and an issue related to the fact that none of the applied filters get considered by the text selection manager.
Relevant source code about that is from the TextView class and from this Editor hidden helper class which I found somehow. Spent some time on it but still can't tell why my filters are ignored.
To #pskink: let cursor be the filtered drawable, I can have:
<ImageView
android:id="#id/1"
android:src="#drawable/cursor_drawable" />
<ImageView
android:id="#id/2" />
The first won't be tinted, but if I call imageView2.setBackground(cursor), then it's tinted.
Also if I have
<item name="android:textSelectHandle">#drawable/cursor_drawable</item>
this affects the edit selection (because I override the default cursor) but it's not tinted, again.
you need to override the default Resources used by your Activity:
// your activity source file
Resources res;
#Override
public Resources getResources() {
if (res == null) {
res = new TintResources(super.getResources());
}
return res;
}
the custom Resources class will override getDrawable() method so you can intercept creating your Drawables and set up the color filter, for example:
class TintResources extends Resources {
public TintResources(Resources resources) {
super(resources.getAssets(), resources.getDisplayMetrics(), resources.getConfiguration());
}
#Override
public Drawable getDrawable(int id) throws NotFoundException {
Drawable d = super.getDrawable(id);
if (id == R.drawable.text_cursor_material) {
// setup #drawable/text_cursor_material
d.setColorFilter(0xff00aa00, PorterDuff.Mode.SRC_IN);
}
return d;
}
}
the same way you can setup other Drawables (#drawable/text_select_handle_*_material), note you need that not direct way since EditText doesn't have getter methods for accessing those Drawables
This is just a partial answer, and we can also consider it quite bad, since it's a workaround. I was able to load just the handles (i.e., the BitmapDrawables) inside the edittext (or any other selection stuff) by pointing at XML files rather than at raw png files. I.e. I set:
<item name="android:textSelectHandleLeft">#drawable/text_select_handle_left_material</item>
<item name="android:textSelectHandleRight">#drawable/text_select_handle_right_material</item>
<item name="android:textSelectHandle">#drawable/text_select_handle_middle_material</item>
<item name="android:textCursorDrawable">#drawable/text_cursor_material</item>
where these are xml drawables like:
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/text_select_handle_left_mtrl_alpha" />
or
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/text_cursor_mtrl_alpha" />
If I filter these drawables, I found them tinted both in views and in selections. So I altered my method like such:
private void setUpTextCursors() {
ColorFilter cf = new PorterDuffColorFilter(mColorControlActivated, PorterDuff.Mode.SRC_IN);
BitmapDrawable left = (BitmapDrawable) getResources().getDrawable(R.drawable.text_select_handle_left_material);
BitmapDrawable middle = (BitmapDrawable) getResources().getDrawable(R.drawable.text_select_handle_middle_material);
BitmapDrawable right = (BitmapDrawable) getResources().getDrawable(R.drawable.text_select_handle_right_material);
// NinePatchDrawable cursor = (NinePatchDrawable) getResources().getDrawable(R.drawable.text_cursor_material);
left.setColorFilter(cf);
right.setColorFilter(cf);
middle.setColorFilter(cf);
// cursor.setColorFilter(cf); this does not work: cursor still white!
}
However, while this works for left, right, and middle, something is still wrong with the 9-patch cursor, because I can't get it tinted.
I'm trying to make a general framework function that makes any Drawable become highlighted when pressed/focused/selected/etc.
My function takes a Drawable and returns a StateListDrawable, where the default state is the Drawable itself, and the state for android.R.attr.state_pressed is the same drawable, just with a filter applied using setColorFilter.
My problem is that I can't clone the drawable and make a separate instance of it with the filter applied. Here is what I'm trying to achieve:
StateListDrawable makeHighlightable(Drawable drawable)
{
StateListDrawable res = new StateListDrawable();
Drawable clone = drawable.clone(); // how do I do this??
clone.setColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY);
res.addState(new int[] {android.R.attr.state_pressed}, clone);
res.addState(new int[] { }, drawable);
return res;
}
If I don't clone then the filter is obviously applied to both states. I tried playing with mutate() but it doesn't help..
Any ideas?
Update:
The accepted answer indeed clones a drawable. It didn't help me though because my general function fails on a different problem. It seems that when you add a drawable to a StateList, it loses all its filters.
Try the following:
Drawable clone = drawable.getConstantState().newDrawable();
If you apply a filter / etc to a drawable created with getConstantState().newDrawable() then all instances of that drawable will be changed as well, since drawables use the constantState as a cache!
So if you color a circle using a color filter and a newDrawable(), you will change the color of all the circles.
If you want to make this drawable updatable without affecting other instances then, then you must mutate that existing constant state.
// To make a drawable use a separate constant state
drawable.mutate()
For a good explanation see:
http://www.curious-creature.org/2009/05/02/drawable-mutations/
http://developer.android.com/reference/android/graphics/drawable/Drawable.html#mutate()
This is what works for me.
Drawable clone = drawable.getConstantState().newDrawable().mutate();
This is my solution, based on this SO question.
The idea is that ImageView gets color filter when user touches it, and color filter is removed when user stops touching it. Only 1 drawable/bitmap is in memory, so no need to waste it. It works as it should.
class PressedEffectStateListDrawable extends StateListDrawable {
private int selectionColor;
public PressedEffectStateListDrawable(Drawable drawable, int selectionColor) {
super();
this.selectionColor = selectionColor;
addState(new int[] { android.R.attr.state_pressed }, drawable);
addState(new int[] {}, drawable);
}
#Override
protected boolean onStateChange(int[] states) {
boolean isStatePressedInArray = false;
for (int state : states) {
if (state == android.R.attr.state_pressed) {
isStatePressedInArray = true;
}
}
if (isStatePressedInArray) {
super.setColorFilter(selectionColor, PorterDuff.Mode.MULTIPLY);
} else {
super.clearColorFilter();
}
return super.onStateChange(states);
}
#Override
public boolean isStateful() {
return true;
}
}
usage:
Drawable drawable = new FastBitmapDrawable(bm);
imageView.setImageDrawable(new PressedEffectStateListDrawable(drawable, 0xFF33b5e5));
I answered a related question here
Basically it seems like StateListDrawables indeed lose their filters. I created a new BitmapDrawale from a altered copy of the Bitmap I originally wanted to use.
Get clone drawable using newDrawable() but make sure it is mutable otherwise your clone effect gone, I used these few lines of code and it is working as expected. getConstantState() may be null as suggested by annotation, so handle this RunTimeException while you cloning drawable.
Drawable.ConstantState state = d.mutate().getConstantState();
if (state != null) {
Drawable drawable = state.newDrawable().mutate();
}
Drawable clone = drawable.mutate().getConstantState().newDrawable().mutate();
in case getConstantState() returns null.
I have an ImageButton which is disabled (non clickable or set as disabled). I want to give an UI feel to the user that it is disabled without using any other image.
Is there any way to do this?
Unlike a regular Button, an ImageButton or a Button that has an image background is not grayed when disabled. You actually have to use another image or to process it in a way it appears grayed.
Should using another image be ok, you can do this by using a <selector> (here associated to a regular Button but this amongs to the same):
/drawable/my_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false"
android:drawable="#drawable/button_gray" /> ***button_gray is a Drawable image***
<item android:state_pressed="true"
android:drawable="#drawable/button_gray" />
<item android:drawable="#drawable/button_red" /> ***button_red is a Drawable image***
</selector>
Please note that in a selector the logic applies a sequential way, item per item. Here, button_red is used all the time but when the button is disabled or being pushed.
Your layout.xml:
<Button android:id="#+id/myButton"
android:background="#drawable/my_selector" ***this is a reference to the selector above ***
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
And should using another image be a problem, other answers (such as #Tronman's or #southerton's) give you ways to programmatically process the image in a way it appears grayed.
#Oleg Vaskevich gave a different solution to the problem here: Disable an ImageButton
His solution allows you to gray-out an ImageButton without creating additional images or using a <selector>.
/**
* Sets the image button to the given state and grays-out the icon.
*
* #param ctxt The context
* #param enabled The state of the button
* #param item The button item to modify
* #param iconResId The button's icon ID
*/
public static void setImageButtonEnabled(Context ctxt, boolean enabled,
ImageButton item, int iconResId) {
item.setEnabled(enabled);
Drawable originalIcon = ctxt.getResources().getDrawable(iconResId);
Drawable icon = enabled ? originalIcon : convertDrawableToGrayScale(originalIcon);
item.setImageDrawable(icon);
}
/**
* Mutates and applies a filter that converts the given drawable to a Gray
* image. This method may be used to simulate the color of disable icons in
* Honeycomb's ActionBar.
*
* #return a mutated version of the given drawable with a color filter applied.
*/
public static Drawable convertDrawableToGrayScale(Drawable drawable) {
if (drawable == null)
return null;
Drawable res = drawable.mutate();
res.setColorFilter(Color.GRAY, Mode.SRC_IN);
return res;
}
I preferred overriding the setEnabled() method in the ImageButton to change the image's alpha property accordingly. So when the button is disabled, the image will be partially transparent and more disabled-looking.
public class CustomImageButton extends ImageButton {
//...
#Override
public void setEnabled(boolean enabled) {
if(this.isEnabled() != enabled) {
this.setImageAlpha(enabled ? 0xFF : 0x3F);
}
super.setEnabled(enabled);
}
}
Elaborating on #tronman answer you can also compose a function that will gray out dynamically loaded drawables (i.e. not from resource, - for example loaded from raw svg files and converted to BitmapDrawables on the fly).
/**
* Sets the specified image buttonto the given state, while modifying or
* "graying-out" the icon as well
*
* #param enabled The state of the menu item
* #param item The menu item to modify
* #param originalIcon The drawable
*/
public static void setImageButtonEnabled(Context ctxt, boolean enabled, ImageButton item, Drawable originalIcon) {
item.setEnabled(enabled);
Drawable res = originalIcon.mutate();
if (enabled)
res.setColorFilter(null);
else
res.setColorFilter(Color.GRAY, PorterDuff.Mode.SRC_IN);
}
If you also have a non-transparent drawable on background (set with android:background) refer to selectors Android: How to Make A Drawable Selector to also modify background.
Using setImageAlpha on the ImageButton, this can be done
While Enabling,
((ImageButton) findViewById(R.id.btnImageButton1)).setEnabled(true);
((ImageButton) findViewById(R.id.btnImageButton1)).setImageAlpha(0xFF);
while disabling,
((ImageButton) findViewById(R.id.btnImageButton1)).setEnabled(false);
((ImageButton) findViewById(R.id.btnImageButton1)).setImageAlpha(0x3F);
As #SnoopDougg suggested a custom ImageButton class might be a nice idea extending the ImageButton and setting the ImageAlpha inside; haven't tried yet but.
You can set it to non clickable and also set the alpha to show that feeling that you mention.
Solution using only xml resource files:
<ImageButton
style="#style/your-style"
android:tint="#color/but_color"
android:src="#drawable/button" />
and color resource but_color (in res/color folder):
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:color="#888" />
<item android:color="?android:attr/colorAccent" />
</selector>
That is, we set color tint of the button (works fine on each Android version if using AndroidX support library). The tint itself is color-state-list. Set colors as you need, here is grey for disabled state, and accent color from theme for enabled state.
We change only color, and only need one image drawable. But note that entire color of button will be changed.
In Kotlin you can utilize Extension functions.
fun ImageButton.enable() {
this.isEnabled = true
this.imageAlpha = 0xFF
}
fun ImageButton.disable() {
this.isEnabled = false
this.imageAlpha = 0x3F
}
myButton.enable()
myButton.disable()
public static void setImageButtonEnabled(#NonNull final ImageView imageView,
final boolean enabled) {
imageView.setEnabled(enabled);
imageView.setAlpha(enabled ? 1.0f : 0.3f);
final Drawable originalIcon = imageView.getDrawable();
final Drawable icon = enabled ? originalIcon : convertDrawableToGrayScale(originalIcon);
imageView.setImageDrawable(icon);
}
private static Drawable convertDrawableToGrayScale(#NonNull Drawable drawable) {
final ColorMatrix matrix = new ColorMatrix();
matrix.setSaturation(0);
final ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
final Drawable mutated = drawable.mutate();
mutated.setColorFilter(filter);
return mutated;
}
If you use Kotlin, you can create an Extension Function instead, so it looks more elegant:
fun ImageView.setImageButtonEnabled(enabled: Boolean){
//Above implementation here
}
and call it using:
yourImageView.setImageButtonEnabled(true/false)
Kotlin extension function to enable/disable an ImageView/ImageButton without IconResId
fun ImageView.setImageViewEnabled(enabled: Boolean) = if(enabled) {
drawable.clearColorFilter()
isEnabled = true
} else {
drawable.colorFilter = PorterDuffColorFilter(Color.GRAY, PorterDuff.Mode.SRC_IN)
isEnabled = false
}
Nope, your image is the differentiating factor.. so if you don't want to change the image then you cannot tell whether the image button is disabled, enabled, pressed.