Membandingkan dua drawable di android


90

Bagaimana membandingkan dua drawable, saya melakukan seperti ini tetapi tidak berhasil

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

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

Jawaban:


150

Perbarui https://stackoverflow.com/a/36373569/1835650

getConstantState () tidak berfungsi dengan baik

Ada cara lain untuk membandingkan:

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

mRemeberPwdadalah ImageViewdalam contoh ini. Jika Anda menggunakan TextView, gunakan getBackground().getConstantStatesaja.


3
Solusi ini berfungsi dan lebih baik karena menghindari konversi Drawable menjadi Bitmap dan bandingkan.
Braj

2
Tidak selalu: WallpaperManager.getInstance (this) .getFastDrawable (). GetConstantState () adalah null.
paulgavrikov

Maaf terlambat menerima ini sebagai jawaban dan mengubah jawaban saya sendiri karena opsi ini tampaknya lebih baik (dan lebih banyak suara positif juga :)). Jadi memeriksa ini sebagai jawaban.
Roshan Jha

Terima kasih, ini adalah jawaban terbaik
satyres

8
Kode ini berfungsi dengan baik pada perangkat yang lebih rendah dari 5.0 tetapi saya mendapatkan kesalahan saat menggunakannya pada perangkat 5.0, adakah yang dapat mengonfirmasi bahwa metode ini berfungsi atau tidak pada Android 5.0 atau lebih tinggi
Phil3992

41

Mengandalkan diri getConstantState()sendiri dapat menghasilkan negatif palsu .

Pendekatan yang saya ambil adalah mencoba membandingkan ConstantState pada contoh pertama, tetapi kembali pada perbandingan Bitmap jika pemeriksaan itu gagal.

Ini harus bekerja di semua kasus (termasuk gambar yang bukan sumber daya) tetapi perhatikan bahwa itu haus memori.

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

Ini 100% benar dan membutuhkan lebih banyak suara positif! Teman-teman, harap uji kode Anda dengan Drawable yang diketahui sebelum segera mengandalkan getConstantState()perbandingan
avalancha

Temuan bagus! Tetapi menurut dokumentasi BitmapDrawable.getBitmap (), getBitmap () mungkin null jadi Anda mungkin ingin memeriksanya juga
PhilLab

Jawaban ini benar dan saya telah memeriksanya setelah debugging beberapa jam dengan pengkodean hanya getConstantState ().
Raghav Satyadev

Untuk amannya, setBoundsdan drawpada salinan sebagai ganti stackoverflow.com/a/25462223/1916449 asli
arekolek

Ini tidak berfungsi dengan BitmapDrawables berwarna (lihat setTintMode / setTint / setTintList). Bitmap dapat berupa byte identik untuk byte tetapi dengan properti rona berbeda. Karena Android SDK tidak menyediakan getter untuk properti tint, mungkin tidak ada cara untuk membuatnya berfungsi dengan drawable berwarna.
Theo

13

Pertanyaan saya adalah hanya membandingkan dua drawable, saya mencoba tetapi tidak bisa mendapatkan metode apa pun yang secara langsung membandingkan dua drawable, namun untuk solusi saya, saya mengubah drawable menjadi bitmap dan kemudian membandingkan dua bitmap dan itu berfungsi.

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

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

Itulah yang saya sarankan kepada Anda, untuk membandingkan drawable menurut jenis drawable.
jeet

1
Anda mungkin juga ingin membandingkan bitmap seperti ini: stackoverflow.com/a/7696320/317889
HGPB

2
Ini sangat berat, jadi pertimbangkan untuk mendaur ulang Bitmap atau Anda akan berakhir di OutOfMemoryError!
paulgavrikov

2
Mengapa Anda dapat membandingkan Bitmap dengan persamaan pointer (==)? Saya berharap Bitmap.equals () dibutuhkan.
Ellen Spertus

@estus Anda benar. Saya menggunakan pertanyaan yang sama untuk objek drawable tidak tahu mengapa beralih ke == untuk objek bitmap sebagai jawaban. Ada cara terima kasih telah menunjukkan dasar ini.
Roshan Jha

9

untuk SDK 21+

ini berfungsi di SDK -21

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

untuk SDK +21 android 5. setel id drawable ke imageview dengan tag

img.setTag(R.drawable.xxx);

dan bandingkan seperti ini

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

solusi ini untuk yang ingin membandingkan drawableid imageviewdengan id drawable.xxx.


Sebenarnya ini berhasil tapi saya agak kaget kenapa tidak ada kemungkinan lain T_T!
error1337

4

Solusi untuk Android 5:

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

4

getDrawable (int) Sekarang Tidak Digunakan Lagi. Gunakan getDrawable (konteks, R.drawable.yourimageid)

Untuk Membandingkan Dua Latar Belakang

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

2
Ini bekerja seperti jimat untuk memperbaiki bug aneh di Android 5. Dalam kode saya, drawable yang sebenarnya dikembalikan context.getResources().getDrawable(R.drawable.***)pada Android 6+ tetapi tidak pada Android 5. Dengan perubahan kecil ini, saya dapat membandingkan drawable latar belakang di semua versi Android dengan sempurna
Jose_GD

3

mungkin mencobanya dengan cara ini:

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

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

atau persiapkan metode yang mengambil dua argumen drawable dan mengembalikan boolean. Dalam metode itu, Anda dapat mengonversi drawable menjadi byte dan membandingkan,

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

periksa jawaban yang diperbarui. jika masih tidak berhasil, periksa drawable Anda. Atau coba lewati drawable yang sama untuk memverifikasi fungsionalitas kode
waqaslam

ya, setelah tidak berhasil, saya berpikir sama untuk mengubah drawable ke bitmap dan kemudian ke byte, izinkan saya mencobanya, terima kasih atas upaya Anda
Roshan Jha

tidak berfungsi, apakah Anda mengujinya? mungkin ada yang salah, tidak bisakah kita membandingkan dua drawable secara langsung?
Roshan Jha

apakah Anda mencobanya dengan menggunakan drawable yang sama untuk e.g R.drawable.abckedua parameter?
waqaslam

halo waqas, periksa metode Anda sekali lagi dan kemudian beri tahu lagi apakah itu berfungsi atau tidak, mungkin saja saya melakukan sesuatu yang salah tetapi tidak berhasil, tetapi kemudian mengubah definisi pertanyaan saya yaitu bagaimana membandingkan dua drawable. drawable ke bitmap dan kemudian byte akan membandingkan bitmap dan byte yang bukan persyaratan saya. jika kita memeriksa metode drawable maka ada metode .equals (object) jadi saya pikir itu harus bekerja secara langsung, tetapi ternyata tidak. Baiklah Anda dapat memeriksa jawaban saya di bawah ini saya mengubah drawable menjadi bitmap dan kemudian membandingkan dua bitmap dan berhasil.
Roshan Jha

2

Oke, saya rasa saya telah menemukan solusi pamungkas untuk ini. Karena AppCompat dan teman-teman, drawable yang disediakan terkadang digelembungkan dalam berbagai bentuk sehingga tidak cukup untuk dilakukan getResources().getBitmap(R.drawable.my_awesome_drawable).

Jadi, untuk mendapatkan instance drawable dari jenis dan bentuk yang sama seperti yang disediakan oleh tampilan, seseorang dapat melakukan ini:

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

Ini berguna saat melakukan tes. Namun, saya tidak akan merekomendasikan melakukan ini dalam produksi. Jika Anda perlu, cache tambahan akan diinginkan untuk menghindari melakukan terlalu banyak refleksi.

Untuk pengujian Expresso, Anda dapat menggunakan ini dengan cukup baik:

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

atau

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

Sebelum Anda harus mendeklarasikan kelas helper ini:

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

Saya sudah menjawab tentang topik serupa di sini: Dapatkan ID drawable di ImageView . Pendekatan ini didasarkan pada pemberian tag pada tampilan dengan id sumber daya yang ditentukan di kustom LayoutInflater. Seluruh proses diotomatiskan oleh pustaka TagView sederhana .

Hasilnya, Anda bisa membandingkan dua drawable hanya dengan idnya:

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

0

Memperluas jawaban dari @vaughandroid, Matcher berikut berfungsi untuk Drawable Vektor yang diwarnai. Anda harus memberikan warna yang digunakan untuk Drawable tersebut.

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

Bandingkan 2 drawable:

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

Jika Anda tidak dapat menemukannya di Drawable.toBitmap(...)sini adalah Drawable.kt


-1

Jika Anda ingin membandingkan dua drawable secara langsung, gunakan kode berikut

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

-2

Ketika Anda menggunakan equals()metode ini digunakan untuk membandingkan konten. Anda harus mencoba ==membandingkan dua objek.

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

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

maka mungkin saja mereka tidak ==, mereka adalah! =
Lucifer

tetapi mereka mengacu pada gambar yang sama dari sumber
Roshan Jha

Saya hanya perlu memeriksa apakah mereka sama atau tidak? Tidak ada metode yang tersedia untuk itu?
Roshan Jha

ya, saya mendapatkan kebutuhan Anda, silakan datang ke ruang obrolan
Lucifer

1
== Bandingkan jika ini adalah objek yang sama, yang bukan n 99.99999999% dari waktu.
paulgavrikov
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.