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());

mRemeberPwdImageView본 실시 예에서. 를 사용하는 TextView경우 getBackground().getConstantState대신 사용하십시오.


3
이 솔루션은 Drawable을 Bitmap으로 변환하고 비교하지 않기 때문에 더 효과적입니다.
Braj 2013-08-09

2
항상 그런 것은 아닙니다. WallpaperManager.getInstance (this) .getFastDrawable (). getConstantState ()가 null입니다.
paulgavrikov 2013

늦게 이것을 대답으로 받아들이고 더 나은 옵션으로 보이므로 내 대답을 변경하여 죄송합니다 (그리고 더 많은 찬성도 :)). 그래서 이것을 답으로 확인하십시오.
Roshan Jha 2014

감사합니다. 이것이 최고의 답변입니다
satyres 2014-08-05

8
장치가 5.0 안드로이드 이상에서 5.0 장치, 캔 누군가의 확인에이 방법의 작동 여부를 그것을 사용하는데 오류가 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;
}

이것은 100 % 사실이며 더 많은 찬성표가 필요합니다! 사람들은 즉시 getConstantState()비교에 의존하기 전에 알려진 드로어 블을 사용하여 코드를 테스트하십시오
avalancha

좋은 결과! 그러나 BitmapDrawable.getBitmap ()의 문서에 따르면 getBitmap ()이 null 일 수
있으므로이 항목

이 대답은 사실이며 getConstantState () 만 코딩하여 몇 시간 동안 디버깅 한 후 확인했습니다.
Raghav Satyadev

안전에 setBounds하고 draw원본 대신 사본에 stackoverflow.com/a/25462223/1916449
arekolek

착색 된 BitmapDrawables에서는 작동하지 않습니다 (setTintMode / setTint / setTintList 참조). 비트 맵은 바이트마다 동일한 바이트 일 수 있지만 색조 속성은 다릅니다. Android SDK는 tint 속성에 대한 getter를 제공하지 않기 때문에 착색 된 드로어 블에서 작동하도록하는 방법이 없을 수 있습니다.
테오

13

내 질문은 두 개의 드로어 블을 비교하는 것이었지만 두 드로어 블을 직접 비교하는 방법을 시도했지만 내 솔루션의 경우 드로어 블을 비트 맵으로 변경 한 다음 두 개의 비트 맵을 비교하면 작동합니다.

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

if(bitmap == bitmap2)
    {
        //Code blcok
    }

드로어 블 유형에 따라 드로어 블을 비교하기 위해 제가 제안한 것입니다.
jeet

1
다음과 같이 비트 맵을 비교할 수도 있습니다. stackoverflow.com/a/7696320/317889
HGPB 2013

2
이것은 매우 무겁기 때문에 비트 맵 재활용을 고려하십시오. 그렇지 않으면 OutOfMemoryError가 발생합니다!
paulgavrikov 2013

2
비트 맵을 포인터 같음 (==)과 비교할 수있는 이유는 무엇입니까? Bitmap.equals ()가 필요할 것으로 예상합니다.
Ellen Spertus 2014

@espertus 당신이 맞습니다. 나는 드로어 블 객체에 대해 동일한 것을 사용했는데 왜 비트 맵 객체에 대해 ==로 바뀌 었는지 모르겠습니다. 이 기본 사항을 지적 해 주셔서 감사합니다.
Roshan Jha 2014 년

9

SDK 21 이상용

이것은 SDK -21에서 작동합니다.

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

SDK +21 android 5. 드로어 블 ID를 태그가있는 imageview로 설정

img.setTag(R.drawable.xxx);

이렇게 비교

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

이 솔루션은의 drawableID를의 imageviewID와 비교하려는 사람을위한 것 입니다 drawable.xxx.


사실이게 효과가 있는데 왜 다른 가능성이 없는지 깜짝이야 T_T!
error1337

4

Android 5 용 솔루션 :

 if(image.getDrawable().getConstantState().equals(image.getContext().getDrawable(R.drawable.something).getConstantState()))

4

getDrawable (int) 은 이제 사용되지 않습니다. 사용 getDrawable (문맥, R.drawable.yourimageid)

두 배경을 비교하려면

Boolean Condition1=v.getBackground().getConstantState().equals(
ContextCompat.getDrawable(getApplicationContext(),R.drawable.***).getConstantState());

2
이것은 Android 5에서 이상한 버그를 수정하는 매력처럼 작동했습니다. 내 코드에서 실제 드로어 블은 context.getResources().getDrawable(R.drawable.***)Android 6 이상 에서 반환 되었지만 Android 5에서는 반환 되지 않았습니다.이 작은 변경으로 모든 Android 버전에서 배경 드로어 블을 완벽하게 비교할 수 있습니다.
Jose_GD dec.

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
  }
}

또는 두 개의 드로어 블 인수를 취하고 부울을 반환하는 메서드를 준비합니다. 이 방법에서 드로어 블을 바이트로 변환하고 비교할 수 있습니다.

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을

예, 성공하지 못한 후 드로어 블을 비트 맵으로 변환 한 다음 바이트로 변환 할 때도 똑같이 생각하고 있습니다. 한 번 시도해 보겠습니다. 노력해 주셔서 감사합니다
Roshan Jha

작동하지 않습니다. 테스트 했습니까? 뭔가 잘못되었을 수 있습니다. 두 드로어 블을 직접 비교할 수는 없나요?
Roshan Jha 2012

e.g R.drawable.abc두 매개 변수로 동일한 드로어 블을 전달해 보셨나요?
waqaslam

안녕하세요 waqas, 방법을 다시 한 번 확인한 다음 작동하는지 여부를 다시 말하십시오. 내가 잘못하고 있지만 작동하지 않았을 가능성이 있지만 두 드로어 블을 비교하는 방법에 대한 내 질문의 정의가 변경됩니다. 드로어 블을 비트 맵으로 변환 한 다음 바이트는 내 요구 사항이 아닌 비트 맵과 바이트를 비교합니다. 드로어 블 메서드를 확인하면 .equals (object) 메서드가 있으므로 직접 작동해야한다고 생각했지만 그렇지 않았습니다. 아래에서 드로어 블을 비트 맵으로 변환 한 다음 두 비트 맵을 비교하고 있으며 작동 중입니다.
Roshan Jha 2012

2

좋아, 나는 이것에 대한 궁극적 인 해결책을 찾은 것 같습니다. AppCompat와 친구들 때문에 제공된 드로어 블이 때때로 다른 형태로 부풀려서 충분하지 않습니다 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);
        }
     }
  }

}


0

비슷한 주제에 대해 이미 대답했습니다 . ImageView에서 드로어 블의 ID를 가져옵니다 . 이 접근 방식은 사용자 정의에서 지정된 리소스 ID로 뷰에 태그를 지정하는 것을 기반으로합니다 LayoutInflater. 전체 프로세스는 간단한 라이브러리 TagView에 의해 자동화됩니다 .

결과적으로 ID만으로 두 드로어 블을 비교할 수 있습니다.

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);

드로어 블 sDraw = getResources (). getDrawable (R.drawable.twt_hover);

if (fDraw.getConstantState().equals(sDraw.getConstantState())) {
    //write your code.
} else {
    //write your code.
}

-2

당신이 사용하는 경우 equals()방법이 내용을 비교하는 데 사용됩니다. ==두 개체를 비교해 보아야 합니다.

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

  if( fDraw == sDraw )
  {
   // Coming
  }
}

그렇다면 그들은 ==가 아닐 수도 있습니다. 그들은! =
Lucifer

하지만 그들은 자원에서 동일한 이미지를 참조
의 Roshan 제이 자

나는 그들이 같은지 아닌지 확인해야합니다. 사용 가능한 방법이 없습니까?
Roshan Jha 2012

나중에, 난, 방 채팅을 귀하의 요구 사항 오세요있어
루시퍼

1
== 이것이 동일한 객체인지 비교합니다. 이것은 시간의 99.99999999 %가 아닙니다.
paulgavrikov 2013
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.