So sánh hai phần mềm có thể kéo được trong Android


90

Làm thế nào để so sánh hai ngăn kéo, tôi đang làm như thế này nhưng không thành công

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

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

Câu trả lời:


150

Cập nhật https://stackoverflow.com/a/36373569/1835650

getConstantState () hoạt động không tốt

Có một cách khác để so sánh:

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

mRemeberPwdlà một ImageViewtrong ví dụ này. Nếu bạn đang sử dụng TextView, hãy sử dụng getBackground().getConstantStatethay thế.


3
Giải pháp này hoạt động và tốt hơn vì nó tránh chuyển đổi Drawable thành Bitmap và so sánh.
Braj

2
Không phải lúc nào: WallpaperManager.getInstance (this) .getFastDrawable (). GetConstantState () là null.
paulgavrikov

Xin lỗi vì đã muộn chấp nhận đây là câu trả lời và thay đổi câu trả lời của riêng tôi vì đây có vẻ là lựa chọn tốt hơn (và nhiều lượt ủng hộ hơn nữa :)). Vì vậy, kiểm tra đây là câu trả lời.
Roshan Jha

Cảm ơn, đây là câu trả lời hay nhất
satyres

8
Mã này hoạt động tốt trên các thiết bị hạ thấp hơn 5,0 nhưng im nhận lỗi sử dụng nó trên 5,0 thiết bị, có thể bất cứ ai xác nhận phương pháp này hoạt động hay không trên Android 5.0 hoặc cao hơn
Phil3992

41

Chỉ dựa vào getConstantState()một mình có thể dẫn đến âm tính sai .

Cách tiếp cận mà tôi đã thực hiện là thử so sánh ConstantState trong trường hợp đầu tiên, nhưng hãy quay lại so sánh Bitmap nếu việc kiểm tra đó không thành công.

Điều này sẽ hoạt động trong mọi trường hợp (bao gồm cả hình ảnh không phải là tài nguyên) nhưng lưu ý rằng bộ nhớ đói.

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

Đây là sự thật 100% và cần nhiều lượt ủng hộ hơn! Mọi người, xin vui lòng kiểm tra mã của bạn với Drawables biết trước ngay lập tức dựa trên getConstantState()so sánh
Patrick

Phát hiện tốt! Tuy nhiên, theo tài liệu của BitmapDrawable.getBitmap (), getBitmap () có thể được null vì vậy bạn có thể muốn kiểm tra này là tốt
PhilLab

Câu trả lời này là đúng và tôi đã kiểm tra điều đó sau khi gỡ lỗi vài giờ với mã hóa chỉ getConstantState ().
Raghav Satyadev

Để an toàn setBoundsdrawtrên một bản sao thay vì stackoverflow.com/a/25462223/1916449
arekolek

Điều này không hoạt động với BitmapDrawables được tô màu (xem setTintMode / setTint / setTintList). Các bitmap có thể là byte giống hệt nhau đối với byte nhưng có các thuộc tính màu khác nhau. Bởi vì Android SDK không cung cấp bất kỳ bộ chuyển đổi nào cho các thuộc tính màu nên có thể không có cách nào để làm cho nó hoạt động với các ngăn kéo được nhuộm màu.
Theo

12

Câu hỏi của tôi là chỉ so sánh hai tệp có thể vẽ được, tôi đã thử nhưng không thể nhận được bất kỳ phương pháp nào so sánh trực tiếp hai tệp có thể kéo được, tuy nhiên đối với giải pháp của tôi, tôi đã thay đổi có thể vẽ thành bitmap và sau đó so sánh hai bitmap và điều đó đang hoạt động.

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

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

đó là những gì tôi đã gợi ý cho bạn, để so sánh có thể kéo được theo loại có thể vẽ.
jeet

1
Bạn cũng có thể muốn so sánh các bitmap như thế này: stackoverflow.com/a/7696320/317889
HGPB

2
Điều này rất nặng, vì vậy hãy xem xét việc tái chế Bitmap nếu không bạn sẽ gặp lỗi OutOfMemoryError!
paulgavrikov

2
Tại sao bạn có thể so sánh Bitmap với bình đẳng con trỏ (==)? Tôi mong đợi Bitmap.equals () là cần thiết.
Ellen Spertus

@espertus Bạn nói đúng. Tôi đã sử dụng tương tự trong câu hỏi cho các đối tượng có thể vẽ được. Tôi không biết tại sao lại chuyển sang == cho đối tượng bitmap trong câu trả lời. Bất kỳ cách nào cảm ơn vì đã chỉ ra điều cơ bản này.
Roshan Jha

9

cho SDK 21+

cái này hoạt động trong SDK -21

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

cho SDK +21 android 5. đặt id có thể vẽ thành chế độ xem hình ảnh có thẻ

img.setTag(R.drawable.xxx);

và so sánh như thế này

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

giải pháp này dành cho những ai muốn so sánh drawableid của imageviewvới id của drawable.xxx.


Thực ra cái này cũng có tác dụng nhưng mình hơi sốc tại sao không có khả năng nào khác T_T!
error1337

4

Giải pháp cho Android 5:

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

4

getDrawable (int) hiện không được dùng nữa. Sử dụng getDrawable (context, R.drawable.yourimageid)

Để so sánh hai nền

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

2
Điều này hoạt động giống như một sự quyến rũ để sửa một lỗi kỳ lạ trên Android 5. Trong mã của tôi, tệp có thể vẽ thực tế đã được trả lại context.getResources().getDrawable(R.drawable.***)trên Android 6+ nhưng không phải trên Android 5. Với thay đổi nhỏ này, tôi có thể so sánh các tệp có thể vẽ nền trên tất cả các phiên bản Android một cách hoàn hảo
Jose_GD

3

có lẽ hãy thử theo cách này:

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

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

hoặc chuẩn bị một phương thức có hai đối số có thể vẽ và trả về boolean. Trong phương pháp đó, bạn có thể chuyển đổi có thể vẽ thành byte và so sánh,

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

kiểm tra câu trả lời cập nhật. nếu vẫn không hoạt động thì hãy kiểm tra các đồ có thể kéo của bạn. Hoặc thử đi cùng drawables để xác minh các chức năng mã
waqaslam

vâng, sau khi không nhận được sự thành công Tôi đang nghĩ đến cùng để chuyển đổi drawables để bitmap và sau đó đến byte, hãy để tôi thử một đó, cảm ơn bạn đã nỗ lực của bạn
Roshan Jha

không hoạt động, bạn đã kiểm tra nó? Có thể có gì đó sai, chúng ta không thể so sánh trực tiếp hai tủ có thể kéo được?
Roshan Jha

bạn đã thử nó truyền cùng một drawable cho e.g R.drawable.abccả hai tham số chưa?
waqaslam

xin chào waqas, hãy kiểm tra lại phương pháp của bạn một lần nữa và sau đó nói lại xem nó có hoạt động hay không, có thể là tôi đang làm gì đó sai nhưng điều đó không hoạt động, nhưng sau đó nó thay đổi định nghĩa câu hỏi của tôi rằng làm thế nào để so sánh hai bảng vẽ. drawable thành bitmap và byte sau đó sẽ so sánh bitmap và byte không phải là yêu cầu của tôi. nếu chúng tôi kiểm tra các phương thức có thể drawable thì sẽ có phương thức .equals (đối tượng) vì vậy tôi nghĩ nó sẽ hoạt động trực tiếp, nhưng nó không. bên dưới tôi đang chuyển đổi có thể vẽ thành bitmap và sau đó so sánh hai bitmap và nó đang hoạt động.
Roshan Jha

2

Ok, tôi nghĩ rằng tôi đã tìm ra giải pháp cuối cùng cho việc này. Vì AppCompat và những người bạn, phần có thể vẽ được cung cấp đôi khi bị thổi phồng ở các dạng khác nhau nên không đủ để làm getResources().getBitmap(R.drawable.my_awesome_drawable).

Vì vậy, để có được một thể hiện có thể vẽ cùng kiểu và biểu mẫu như được cung cấp bởi dạng xem, người ta có thể làm điều này:

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

Điều này rất hữu ích khi làm các bài kiểm tra. Tuy nhiên, tôi không khuyên bạn nên làm điều này trong sản xuất. Nếu bạn cần, bạn nên sử dụng thêm bộ nhớ đệm để tránh phản ánh quá nhiều.

Đối với các bài kiểm tra Expresso, bạn có thể sử dụng điều này khá độc đáo:

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

hoặc là

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

Trước khi bạn phải khai báo lớp trợ giúp này:

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

Tôi đã trả lời về chủ đề tương tự ở đây: Lấy ID của một drawable trong ImageView . Phương pháp này dựa trên việc gắn thẻ một chế độ xem với một id tài nguyên được chỉ định trong tùy chỉnh LayoutInflater. Toàn bộ quy trình được tự động hóa bằng TagView thư viện đơn giản .

Do đó, bạn có thể so sánh hai bảng có thể kéo chỉ bằng id của chúng:

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

0

Mở rộng câu trả lời từ @vaughandroid, Matcher sau hoạt động cho Vector Drawable được nhuộm màu. Bạn phải cung cấp tông màu đã được sử dụng cho 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

So sánh 2 có thể vẽ:

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

Nếu bạn không thể tìm thấy Drawable.toBitmap(...)ở đây, nó là Drawable.kt


-1

nếu bạn muốn so sánh trực tiếp hai có thể kéo thì hãy sử dụng mã sau

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

Khi bạn đang sử dụng equals()phương pháp, nó được sử dụng để so sánh các nội dung. bạn nên thử ==so sánh hai đối tượng.

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

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

thì có thể họ không phải là ==, họ là vậy! =
Lucifer

nhưng họ đề cập đến cùng một hình ảnh từ các nguồn lực
Roshan Jha

Tôi chỉ cần kiểm tra xem chúng có bằng nhau hay không? Không có bất kỳ phương pháp nào có sẵn cho điều đó?
Roshan Jha

ya, tôi đã nhận được yêu cầu của bạn, vui lòng đến phòng trò chuyện
Lucifer

1
== So sánh nếu đây là cùng một đối tượng, không phải là 99,99999999% thời gian.
paulgavrikov
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.