Сравнение двух чертежей в Android

90

Как сравнить два чертежа, я делаю так, но не имею успеха

public void MyClick(View view)
{
 Drawable fDraw = view.getBackground();
 Drawable sDraw = getResources().getDrawable(R.drawable.twt_hover);

  if(fDraw.equals(sDraw))
  {
   //Not coming
  }
}
Рошан Джа
источник

Ответы:

150

Обновите https://stackoverflow.com/a/36373569/1835650

getConstantState () работает не очень хорошо

Есть еще один способ сравнить:

mRememberPwd.getDrawable().getConstantState().equals
            (getResources().getDrawable(R.drawable.login_checked).getConstantState());

mRemeberPwdявляется ImageViewв этом примере. Если вы используете TextView, используйте getBackground().getConstantStateвместо него.

Меджонжан
источник
3
Это решение работает и лучше, поскольку позволяет избежать преобразования Drawable в Bitmap и сравнения.
Braj
2
Не всегда: WallpaperManager.getInstance (this) .getFastDrawable (). GetConstantState () имеет значение null.
paulgavrikov
Извините за то, что поздно принял это как ответ и изменил свой ответ, так как это кажется лучшим вариантом (и еще больше голосов :)). Так что проверим это как ответ.
Рошан Джа
Спасибо, это лучший ответ
satyres
8
Этот код отлично работает на устройствах ниже 5.0, но я получаю ошибки, используя его на устройстве 5.0, может ли кто-нибудь подтвердить, что этот метод работает или нет на Android 5.0 или выше
Phil3992
41

Полагаться getConstantState()только на одного может привести к ложным отрицаниям .

Подход, который я использовал, заключается в том, чтобы попытаться сравнить ConstantState в первом экземпляре, но вернуться к сравнению Bitmap, если эта проверка не удалась.

Это должно работать во всех случаях (включая изображения, которые не являются ресурсами), но учтите, что это требует памяти.

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;
}
vaughandroid
источник
Это на 100% правда и нужно больше голосов! Люди, пожалуйста, проверьте свой код с помощью известных Drawables, прежде чем сразу полагаться на getConstantState()сравнение
лавина,
Хорошие выводы! Но согласно документации BitmapDrawable.getBitmap (), getBitmap () может иметь значение null, поэтому вы можете также проверить это
PhilLab
Этот ответ верен, и я проверил это после нескольких часов отладки с кодированием только getConstantState ().
Raghav
На всякий случай setBoundsи drawна копии вместо оригинала stackoverflow.com/a/25462223/1916449
arekolek
Это не работает с тонированными BitmapDrawables (см. SetTintMode / setTint / setTintList). Растровые изображения могут быть идентичными байтом за байтом, но с разными свойствами оттенка. Поскольку Android SDK не предоставляет никаких геттеров для свойств оттенка, может не быть способа заставить его работать с тонированными чертежами.
Тео
13

Мой вопрос заключался в том, чтобы просто сравнить два чертежа, я попытался, но не смог получить какой-либо метод, который напрямую сравнивает два чертежа, однако для своего решения я изменил рисование на растровое изображение, а затем сравнил два растровых изображения, и это работает.

Bitmap bitmap = ((BitmapDrawable)fDraw).getBitmap();
Bitmap bitmap2 = ((BitmapDrawable)sDraw).getBitmap();

if(bitmap == bitmap2)
    {
        //Code blcok
    }
Рошан Джа
источник
это то, что я предлагал вам, сравнивать возможности рисования в зависимости от типа рисования.
jeet
1
Вы также можете сравнить растровые изображения следующим образом: stackoverflow.com/a/7696320/317889
HGPB
2
Это очень сложно, поэтому подумайте об утилизации растровых изображений, иначе вы получите OutOfMemoryError!
paulgavrikov
2
Почему можно сравнивать растровые изображения с равенством указателей (==)? Я ожидал, что понадобится Bitmap.equals ().
Эллен Спертус
@espertus Вы правы. Я использовал то же самое в вопросе для рисованных объектов, не знаю, почему в ответе перешел к == для растрового объекта. В любом случае спасибо за указание на этот основной.
Рошан Джа
9

для SDK 21+

это работает в SDK-21

mRememberPwd.getDrawable().getConstantState().equals
        (getResources().getDrawable(R.drawable.login_checked).getConstantState())

для SDK +21 android 5. установите выводимый идентификатор для просмотра изображений с тегом

img.setTag(R.drawable.xxx);

и сравните вот так

if ((Integer) img.getTag() == R.drawable.xxx)
{
....your code
}

это решение для тех, кто хочет сравнить drawableидентификатор imageviewс идентификатором drawable.xxx.

тохид
источник
На самом деле это работает, но я немного шокирован, почему нет другой возможности T_T!
error1337
4

Решение для Android 5:

 if(image.getDrawable().getConstantState().equals(image.getContext().getDrawable(R.drawable.something).getConstantState()))
Тьяго Сантос
источник
4

getDrawable (int) теперь не рекомендуется. Используйте getDrawable (context, R.drawable.yourimageid)

Сравнить два фона

Boolean Condition1=v.getBackground().getConstantState().equals(
ContextCompat.getDrawable(getApplicationContext(),R.drawable.***).getConstantState());
РАДЖЕШ КУМАР АРУМУГАМ
источник
2
Это сработало как шарм, чтобы исправить странную ошибку на Android 5. В моем коде фактический drawable был возвращен context.getResources().getDrawable(R.drawable.***)на Android 6+, но не был на Android 5. С этим небольшим изменением я могу безупречно сравнивать фоновые рисунки во всех версиях Android.
Jose_GD
3

возможно, попробуй вот так:

public void MyClick(View view)
{
 Drawable fDraw = view.getBackground();
 Drawable sDraw = getResources().getDrawable(R.drawable.twt_hover);

  if(fDraw.hashCode() == sDraw.hashCode())
  {
   //Not coming
  }
}

или подготовьте метод, который принимает два аргумента и возвращает логическое значение. В этом методе вы можете преобразовать drawable в байты и сравнить,

public boolean compareDrawable(Drawable d1, Drawable d2){
    try{
        Bitmap bitmap1 = ((BitmapDrawable)d1).getBitmap();
        ByteArrayOutputStream stream1 = new ByteArrayOutputStream();
        bitmap1.compress(Bitmap.CompressFormat.JPEG, 100, stream1);
        stream1.flush();
        byte[] bitmapdata1 = stream1.toByteArray();
        stream1.close();

        Bitmap bitmap2 = ((BitmapDrawable)d2).getBitmap();
        ByteArrayOutputStream stream2 = new ByteArrayOutputStream();
        bitmap2.compress(Bitmap.CompressFormat.JPEG, 100, stream2);
        stream2.flush();
        byte[] bitmapdata2 = stream2.toByteArray();
        stream2.close();

        return bitmapdata1.equals(bitmapdata2);
    }
    catch (Exception e) {
        // TODO: handle exception
    }
    return false;
}
вакаслам
источник
проверьте обновленный ответ. если все еще не работает, проверьте свои чертежи. Или попробуйте передать те же чертежи, чтобы проверить работоспособность кода
waqaslam
да, не добившись успеха, я думаю то же самое о преобразовании чертежей в растровые изображения, а затем в байты, позвольте мне попробовать это, спасибо за ваши усилия
Рошан Джа
не работает, вы это тестировали? Может быть, что-то не так, нельзя напрямую сравнить два чертежа?
Рошан Джа
вы пробовали передавать тот же рисунок для e.g R.drawable.abcобоих параметров?
waqaslam 03
привет, вакас, проверьте свой метод еще раз, а затем еще раз скажите, работает он или нет, возможно, я делаю что-то не так, но это не сработало, но тогда это меняет определение моего вопроса о том, как сравнить два чертежа. можно преобразовать в растровое изображение, а затем байты будут сравнивать растровое изображение и байты, что не является моим требованием. если мы проверяем методы рисования, тогда есть метод .equals (object), поэтому я думал, что он должен работать напрямую, но это не так. ниже я конвертирую рисование в растровое изображение, а затем сравниваю два растровых изображения, и он работает.
Рошан Джа
2

Хорошо, я думаю, что нашел окончательное решение для этого. Из-за AppCompat и друзей предоставляемый drawable иногда раздувается в разных формах, поэтому этого недостаточно getResources().getBitmap(R.drawable.my_awesome_drawable).

Итак, чтобы получить доступный для рисования экземпляр того же типа и формы, что и в представлении, можно сделать следующее:

public static Drawable drawableFrom(View view, @DrawableRes int drawableId) {
    Context context = view.getContext();
    try {
        View dummyView = view.getClass().getConstructor(Context.class).newInstance(context);
        dummyView.setBackgroundResource(drawableId);
        return dummyView.getBackground();
    } catch (Exception e) {
      return ResourcesCompat.getDrawable(context.getResources(), drawableId, null);
    }
}

Это полезно при проведении тестов. Однако я бы не рекомендовал делать это в продакшене. Если вам нужно, было бы желательно дополнительное кеширование, чтобы избежать слишком большого количества отражений.

Для тестов Expresso вы можете использовать это довольно хорошо:

onView(withDrawable(R.drawable.awesome_drawable))
  .check(matches(isDisplayed()));

или же

onView(withId(R.id.view_id))
  .check(matches(withDrawable(R.drawable.awesome_drawable)));

Прежде чем вам нужно будет объявить этот вспомогательный класс:

public class CustomMatchers {

  public static Matcher<View> withDrawable(@DrawableRes final int drawableId) {
     return new DrawableViewMatcher(drawableId);
  }
  private static class DrawableViewMatcher extends TypeSafeMatcher<View> {

     private final int expectedId;
     private String resourceName;

     private enum DrawableExtractionPolicy {
        IMAGE_VIEW {
          @Override
          Drawable findDrawable(View view) {
             return view instanceof ImageView ? ((ImageView) view).getDrawable() : null;
          }
        },
        TEXT_VIEW_COMPOUND {
          @Override
          Drawable findDrawable(View view) {
             return view instanceof TextView ? findFirstCompoundDrawable((TextView) view) : null;
          }
        },
        BACKGROUND {
          @Override
          Drawable findDrawable(View view) {
             return view.getBackground();
          }
        };

        @Nullable
        private static Drawable findFirstCompoundDrawable(TextView view) {
          for (Drawable drawable : view.getCompoundDrawables()) {
             if (drawable != null) {
                return drawable;
             }
          }
          return null;
        }

        abstract Drawable findDrawable(View view);

     }

     private DrawableViewMatcher(@DrawableRes int expectedId) {
        this.expectedId = expectedId;
     }

     @Override
     protected boolean matchesSafely(View view) {
        resourceName = resources(view).getResourceName(expectedId);
        return haveSameState(actualDrawable(view), expectedDrawable(view));
     }

     private boolean haveSameState(Drawable actual, Drawable expected) {
        return actual != null && expected != null && areEqual(expected.getConstantState(), actual.getConstantState());
     }

     private Drawable actualDrawable(View view) {
        for (DrawableExtractionPolicy policy : DrawableExtractionPolicy.values()) {
          Drawable drawable = policy.findDrawable(view);
          if (drawable != null) {
             return drawable;
          }
        }
        return null;
     }

     private boolean areEqual(Object first, Object second) {
        return first == null ? second == null : first.equals(second);
     }

     private Drawable expectedDrawable(View view) {
        return drawableFrom(view, expectedId);
     }

     private static Drawable drawableFrom(View view, @DrawableRes int drawableId) {
        Context context = view.getContext();
        try {
          View dummyView = view.getClass().getConstructor(Context.class).newInstance(context);
          dummyView.setBackgroundResource(drawableId);
          return dummyView.getBackground();
        } catch (Exception e) {
          return ResourcesCompat.getDrawable(context.getResources(), drawableId, null);
        }
     }

     @NonNull
     private Resources resources(View view) {
        return view.getContext().getResources();
     }

     @Override
     public void describeTo(Description description) {
        description.appendText("with drawable from resource id: ");
        description.appendValue(expectedId);
        if (resourceName != null) {
          description.appendValueList("[", "", "]", resourceName);
        }
     }
  }

}
паблиско
источник
1

Используйте getTag () и setTag () для сравнения

Пуджа Акшантал
источник
0

Я уже отвечал на аналогичную тему здесь: Получите идентификатор чертежа в ImageView . Подход основан на пометке представления с указанным идентификатором ресурса в custom LayoutInflater. Весь процесс автоматизирован простой библиотекой TagView .

В результате вы можете сравнить два чертежа только по их идентификаторам:

TagViewUtils.getTag(view, ViewTag.VIEW_BACKGROUND.id) == R.drawable.twt_hover
Богдан Корнев
источник
0

Расширяя ответ от @vaughandroid, следующий Matcher работает для окрашенного Vector Drawable. Вы должны предоставить оттенок, который использовался для 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) {

        }
    };
}
Иеремия Эйкенберг
источник
0

Сравните 2 чертежа:

drawable1.constantState == drawable2.constantState
            || drawable1.toBitmap().sameAs(drawable2.toBitmap())

Если вы не можете найти Drawable.toBitmap(...)вот это Drawable.kt

Бенни
источник
-1

если вы хотите напрямую сравнить два чертежа, используйте следующий код

Возможность рисования fDraw = getResources (). GetDrawable (R.drawable.twt_hover);

Drawable sDraw = getResources (). GetDrawable (R.drawable.twt_hover);

if (fDraw.getConstantState().equals(sDraw.getConstantState())) {
    //write your code.
} else {
    //write your code.
}
Addon.mahesh
источник
-2

Когда вы используете equals()метод, он используется для сравнения содержимого. вы должны попробовать ==сравнить два объекта.

public void MyClick(View view)
{
 Drawable fDraw = view.getBackground();
 Drawable sDraw = getResources().getDrawable(R.drawable.twt_hover);

  if( fDraw == sDraw )
  {
   // Coming
  }
}
Люцифер
источник
тогда возможно, что они не ==, они есть! =
Люцифер
но они ссылаются на одно и то же изображение с ресурсов
Рошан Джа
Мне просто нужно проверить, равны ли они или нет? Для этого нет никакого метода?
Рошан Джа
да, у меня есть ваше требование, пожалуйста, заходите в чат-комнату
Люцифер
1
== Сравнивает, является ли это одним и тем же объектом, а в 99.99999999% случаев это не так.
paulgavrikov