Android'de iki çekmeceyi karşılaştırma


90

İki çekmeceyi nasıl karşılaştırırım, böyle yapıyorum ama başarılı olamıyorum

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

  if(fDraw.equals(sDraw))
  {
   //Not coming
  }
}

Yanıtlar:


150

Güncelleme https://stackoverflow.com/a/36373569/1835650

getConstantState () iyi çalışmıyor

Karşılaştırmanın başka bir yolu var:

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

mRemeberPwdBir olan ImageViewbu örnekte. A kullanıyorsanız TextView, getBackground().getConstantStatebunun yerine kullanın.


3
Bu çözüm, Drawable'ı Bitmap'e dönüştürmekten ve karşılaştırmaktan kaçındığı için daha iyi çalışır.
Braj

2
Her zaman değil: WallpaperManager.getInstance (bu) .getFastDrawable (). GetConstantState () null.
paulgavrikov

Bunu yanıt olarak geç kabul ettiğim ve kendi cevabımı değiştirdiğim için özür dilerim, çünkü bu daha iyi bir seçenek (ve daha fazla olumlu oy da :)). Yani bunu cevap olarak kontrol ediyorum.
Roshan Jha

Teşekkürler, bu en iyi cevap
satyres

8
Cihazlar 5.0 android veya daha yüksek bir 5.0 cihaz, kutu kimse onayla bu yöntem eser ya da değil bunu kullanarak elde hataları 5.0'dan düşürür ama im üzerindeki bu kod inşaat büyük
Phil3992

41

getConstantState()Tek başına güvenmek yanlış negatiflere neden olabilir .

Benim aldığım yaklaşım, ConstantState'i ilk örnekte karşılaştırmayı denemek, ancak bu kontrol başarısız olursa bir Bitmap karşılaştırmasına geri dönmek.

Bu her durumda çalışmalıdır (kaynak olmayan görüntüler dahil) ancak hafızaya aç olduğunu unutmayın.

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

Bu% 100 doğrudur ve daha fazla oylamaya ihtiyaç duyar! Millet, lütfen hemen getConstantState()karşılaştırmaya güvenmeden önce kodunuzu bilinen Drawables ile test edin
avalancha

İyi bulgular! Ancak BitmapDrawable.getBitmap () belgelerine göre getBitmap () boş olabilir, bu yüzden bunu da kontrol etmek isteyebilirsiniz
PhilLab

Bu cevap doğrudur ve birkaç saat hata ayıkladıktan sonra sadece getConstantState () kodlamasıyla bunu kontrol ettim.
Raghav Satyadev

Güvenli olması, için setBoundsve drawyerine orijinal bir kopyasını stackoverflow.com/a/25462223/1916449
arekolek

Bu, renkli BitmapDrawables ile çalışmaz (bkz. SetTintMode / setTint / setTintList). Bit eşlemler, bayt için aynı bayt olabilir, ancak farklı renk tonu özelliklerine sahip olabilir. Android SDK, renk tonu özellikleri için herhangi bir alıcı sağlamadığından, renklendirilmiş çekmecelerle çalışmasını sağlamanın bir yolu olmayabilir.
Theo

13

Sorum sadece iki çekilebilirliği karşılaştırmak içindi, denedim ama iki çekilebilirliği doğrudan karşılaştıran herhangi bir yöntem bulamadım, ancak çözümüm için çizilebilirliği bitmap olarak değiştirdim ve ardından iki bitmap'i karşılaştırdım ve bu çalışıyor.

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

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

İşte size önerdiğim şey, çekilebilir tipe göre çekilebilirliği karşılaştırmanız.
jeet

1
Ayrıca, bitmap'leri bunun gibi karşılaştırmak isteyebilirsiniz: stackoverflow.com/a/7696320/317889
HGPB

2
Bu çok ağırdır, bu nedenle Bitmap'leri geri dönüştürmeyi düşünün, yoksa bir OutOfMemoryError hatasıyla karşılaşırsınız!
paulgavrikov

2
Bitmap'leri neden işaretçi eşitliğiyle (==) karşılaştırabilirsiniz? Bitmap.equals () 'a ihtiyaç duyulmasını beklerdim.
Ellen Spertus

@espertus Haklısın. Ben de söz konusu çekilebilir nesneler için aynı şeyi kullandım, yanıt olarak bitmap nesnesi için neden == olarak çevrildiğini bilmiyorum. Bu temele işaret ettiğiniz için herhangi bir şekilde teşekkürler.
Roshan Jha

9

SDK 21+ için

bu SDK -21'de çalışır

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

SDK +21 için android 5. çekilebilir kimliği etiketle görüntü görünümüne ayarlayın

img.setTag(R.drawable.xxx);

ve bunun gibi karşılaştır

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

bu çözüm, drawableid imageviewile id'yi karşılaştırmak isteyenler içindir drawable.xxx.


Aslında bu işe yarıyor ama neden başka bir T_T olasılığı olmadığı için şok oldum!
error1337

4

Android 5 için çözüm:

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

4

getDrawable (int) Artık Kullanımdan Kaldırıldı. GetDrawable (bağlam, R.drawable.yourimageid) kullanın

İki Arka Planı Karşılaştırmak İçin

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

2
Bu, Android 5'te tuhaf bir hatayı düzeltmek için bir cazibe gibi çalıştı. Kodumda, gerçek çekilebilir dosya context.getResources().getDrawable(R.drawable.***)Android 6+ ile birlikte döndürüldü, ancak Android 5'te değildi. Bu küçük değişiklikle, tüm Android sürümlerinde arka plandaki çizimleri kusursuz bir şekilde karşılaştırabilirim
Jose_GD

3

belki şu şekilde deneyin:

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

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

veya iki çekilebilir argüman alan ve boolean döndüren bir yöntem hazırlayın. Bu yöntemde, çizilebilirliği bayta dönüştürebilir ve karşılaştırabilirsiniz,

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

güncellenmiş yanıtı kontrol edin. hala çalışmıyorsa çekmecelerinizi kontrol edin. Veya kodun işlevselliğini doğrulamak için aynı çekilebilir
öğeleri

evet, başarı elde edemedikten sonra, çekilebilirleri bitmap'e ve sonra bayta dönüştürmek için de aynı şeyi düşünüyorum, bunu deneyeyim, çabalarınız için teşekkür ederim
Roshan Jha

çalışmıyor, test ettin mi? yanlış bir şeyler olabilir, iki çekmeceyi doğrudan karşılaştıramaz mıyız?
Roshan Jha

e.g R.drawable.abcher iki parametre için aynı çekilebilirliği geçirmeyi denediniz mi?
waqaslam

merhaba waqas, yönteminizi bir kez daha kontrol edin ve sonra çalışıp çalışmadığını tekrar söyleyin, yanlış bir şey yapmam mümkün olabilir ama bu işe yaramadı, ancak daha sonra iki çekmecenin nasıl karşılaştırılacağına dair sorumun tanımını değiştiriyor. bitmap'e çekilebilir ve sonra baytlar, benim ihtiyacım olmayan bitmap ve baytları karşılaştırır. eğer çekilebilir yöntemleri kontrol edersek, o zaman method .equals (nesne) vardır, bu yüzden doğrudan çalışması gerektiğini düşündüm, ancak çalışmadı. aşağıda Drawable'ı bitmap'e dönüştürüyorum ve ardından iki bitmap'i karşılaştırıyorum ve çalışıyor.
Roshan Jha

2

Tamam, sanırım bunun için nihai çözümü buldum. AppCompat ve arkadaşları nedeniyle, sağlanan çekmece bazen farklı şekillerde şişirildiğinden bunu yapmak yeterli değildir getResources().getBitmap(R.drawable.my_awesome_drawable).

Dolayısıyla, görünüm tarafından sağlananla aynı tür ve formda çekilebilir bir örnek elde etmek için bunu yapabilirsiniz:

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

Bu, testler yaparken kullanışlıdır. Ancak bunu üretimde yapmayı tavsiye etmem. Gerekirse, çok fazla yansıtma yapmaktan kaçınmak için fazladan önbelleğe alma istenebilir.

Expresso testleri için bunu oldukça güzel bir şekilde kullanabilirsiniz:

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

veya

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

Bu yardımcı sınıfı bildirmeden önce:

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

Buradaki benzer konuyu zaten yanıtladım: ImageView'da bir çekilebilir ürünün kimliğini alın . Yaklaşım, bir görünümü özelde belirtilen bir kaynak kimliğiyle etiketlemeye dayanır LayoutInflater. Tüm süreç basit bir TagView kitaplığı ile otomatikleştirilir .

Sonuç olarak, iki çekilebilir öğeyi yalnızca kimliklerine göre karşılaştırabilirsiniz:

TagViewUtils.getTag(view, ViewTag.VIEW_BACKGROUND.id) == R.drawable.twt_hover

0

@Vaughandroid'in cevabını genişleten aşağıdaki Eşleştirici, renkli bir Vektör Çizilebilir için çalışıyor. Drawable için kullanılan renk tonunu sağlamanız gerekir.

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 çekmeceyi karşılaştırın:

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

Drawable.toBitmap(...)Burada bulamazsanız Drawable.kt


-1

İki çekmeceyi doğrudan karşılaştırmak istiyorsanız, aşağıdaki kodu kullanın

Çekilebilir fDraw = getResources (). GetDrawable (R.drawable.twt_hover);

Çekilebilir sDraw = getResources (). GetDrawable (R.drawable.twt_hover);

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

-2

Kullandığınız zaman equals()yöntemini içindekileri karşılaştırmak için kullanılır. ==iki nesneyi karşılaştırmayı denemelisiniz .

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

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

o zaman == olmamaları mümkün olabilir, onlar! =
Lucifer

ancak kaynaklardan aynı görüntüyü belirtirseniz
Roshan JHA

Sadece eşit olup olmadıklarını kontrol etmem gerekiyor, bunun için herhangi bir yöntem yok mu?
Roshan Jha

ya, ihtiyacın var, lütfen sohbet odasına gel
Lucifer

1
== Bunun aynı nesne olup olmadığını,% 99,99999999 oranında olmadığını karşılaştırır.
paulgavrikov
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.