比较android中的两个drawables

时间:2012-02-03 07:38:53

标签: android

如何比较两个drawable,我这样做但没有取得任何成功

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

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

14 个答案:

答案 0 :(得分:148)

<强>更新 https://stackoverflow.com/a/36373569/1835650

getConstantState()效果不佳

还有另一种比较方法:

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

mRemeberPwd在此示例中为ImageView。如果您使用的是TextView,请改用getBackground().getConstantState

答案 1 :(得分:34)

仅依靠getConstantState()可能会导致false negatives

我采用的方法是尝试比较第一个实例中的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;
}

答案 2 :(得分:11)

我的问题是仅仅比较两个drawable,我试过但是没有得到任何直接比较两个drawable的方法,但是对于我的解决方案我改变了drawable到位图然后比较两个位图,这是有效的。

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

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

答案 3 :(得分:5)

for SDK 21+

这适用于SDK -21

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

for SDK +21 android 5。 使用标记

将drawable id设置为imageview
img.setTag(R.drawable.xxx);

并像这样比较

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

此解决方案适用于想要将drawable ID为imageview且ID为drawable.xxx的人。

答案 4 :(得分:4)

Android 5的解决方案:

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

答案 5 :(得分: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参数并返回boolean的方法。在该方法中,您可以将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;
}

答案 6 :(得分: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);
        }
     }
  }

}

答案 7 :(得分:1)

  

使用getTag()和setTag()进行比较

答案 8 :(得分:1)

getDrawable(int)现已弃用。使用 getDrawable(context,R.drawable.yourimageid)

比较两个背景

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

答案 9 :(得分:0)

我已经在这里回答了类似的话题:Get the ID of a drawable in ImageView。 该方法基于在自定义GeckoWebBrowser1.Navigate("www.google.com")中使用指定的资源ID标记视图。整个过程由一个简单的库TagView自动完成。

因此,您可以仅通过ID来比较两个drawable:

Load

答案 10 :(得分: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) {

        }
    };
}

答案 11 :(得分:0)

比较2个可绘制对象:

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

如果找不到Drawable.toBitmap(...),这里是Drawable.kt

答案 12 :(得分:-1)

如果你想直接比较两个drawable,那么使用下面的代码

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

答案 13 :(得分:-2)

当您使用equals()方法时,它用于比较内容。您应该尝试==来比较两个对象。

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

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