My question was for just comparing two drawables, I tried but could not get any method that directly compare two drawables,however for my solution i changed drawable to bitmap and then comparing two bitmaps and that is working.
Relying on getConstantState() alone can result in false negatives.
The approach I've taken is to try comparing the ConstantState in the first instance, but fall back on a Bitmap comparison if that check fails.
This should work in all cases (including images which aren't resources) but note that it is memory hungry.
public static boolean areDrawablesIdentical(Drawable drawableA, Drawable drawableB) {
Drawable.ConstantState stateA = drawableA.getConstantState();
Drawable.ConstantState stateB = drawableB.getConstantState();
// If the constant state is identical, they are using the same drawable resource.
// However, the opposite is not necessarily true.
return (stateA != null && stateB != null && stateA.equals(stateB))
|| getBitmap(drawableA).sameAs(getBitmap(drawableB));
}
public static Bitmap getBitmap(Drawable drawable) {
Bitmap result;
if (drawable instanceof BitmapDrawable) {
result = ((BitmapDrawable) drawable).getBitmap();
} else {
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
// Some drawables have no intrinsic width - e.g. solid colours.
if (width <= 0) {
width = 1;
}
if (height <= 0) {
height = 1;
}
result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
}
return result;
}
Ok, I think I've found the ultimate solution for this. Because of AppCompat and friends, the drawable provided is sometimes inflated in different forms so it's not enough to do getResources().getBitmap(R.drawable.my_awesome_drawable).
So, in order to get a drawable instance of the same type and form as provided by the view one can do this:
This is useful when doing tests. However, I would not recommend doing this in production. If you need to, extra caching would be desirable to avoid doing too much reflection.
I already answered on the similar topic here: Get the ID of a drawable in ImageView.
The approach is based on tagging a view with a specified resource id in the custom LayoutInflater. Whole process is automated by a simple library TagView.
As a result, you can compare two drawables just by their ids:
Expanding on the answer from @vaughandroid the following Matcher works for a Vector Drawable that is tinted. You have to provide the tint that was used for the Drawable.
public static Matcher<View> compareVectorDrawables(final int imageId, final int tintId) {
return new TypeSafeMatcher<View>() {
@Override
protected boolean matchesSafely(View target) {
if (!(target instanceof ImageView)) {
return false;
}
ImageView imageView = (ImageView) target;
if (imageId < 0) {
return imageView.getDrawable() == null;
}
Resources resources = target.getContext().getResources();
Drawable expectedDrawable = resources.getDrawable(imageId, null);
if (expectedDrawable == null) {
return false;
}
Drawable imageDrawable = imageView.getDrawable();
ColorFilter imageColorFilter = imageDrawable.getColorFilter();
expectedDrawable.setColorFilter(imageColorFilter);
expectedDrawable.setTintList(target.getResources()
.getColorStateList(tintId, null));
boolean areSame = areDrawablesIdentical(imageDrawable, expectedDrawable);
return areSame;
}
public boolean areDrawablesIdentical(Drawable drawableA, Drawable drawableB) {
Drawable.ConstantState stateA = drawableA.getConstantState();
Drawable.ConstantState stateB = drawableB.getConstantState();
// If the constant state is identical, they are using the same drawable resource.
// However, the opposite is not necessarily true.
return (stateA != null && stateB != null && stateA.equals(stateB))
|| getBitmap(drawableA).sameAs(getBitmap(drawableB));
}
public Bitmap getBitmap(Drawable drawable) {
Bitmap result;
if (drawable instanceof BitmapDrawable) {
result = ((BitmapDrawable) drawable).getBitmap();
} else {
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
// Some drawables have no intrinsic width - e.g. solid colours.
if (width <= 0) {
width = 1;
}
if (height <= 0) {
height = 1;
}
result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
}
return result;
}
@Override
public void describeTo(Description description) {
}
};
}