基础不学好,加班跑不了(一)之ImageView

题外话

今天看到一篇文章,提到美国现总统唐纳德·特朗普和前总统贝拉克·侯赛因·奥巴马在任职期间对中国的影响,提到特朗普政府对中国是烫水煮青蛙,而奥巴马政府是温水煮青蛙。烫水虽然暂时是痛苦的,但能让我们立马清醒过来。美国政府自然是为美国人民考虑的。郑强教授也提到过,中国是个神奇的国家,越是对其搞封锁,反倒是越能干出花样来。

前言

本篇主要记录在开发过程中由于部分基础不扎实导致的一些“加班”情况(浪费了太多时间啦)。

关于ImageView组件方面的一些细节就记录在本篇内。

setColorFilter

ImageView#setColorFilter(int color, PorterDuff.Mode mode))

setColorFilter()用于给ImageView内容进行着色(tint),即改变原有内容的颜色。

错误

而小编一开始写的代码如下:

1
2
3
4
5
6
ImageView iv;

...

iv.setBackgroundResource(R.drawable.ic_setting);
iv.setColorFilter(ContextCompat.getColor(this, R.color.colorPrimary), PorterDuff.Mode.SRC_IN);

结果没有setColorFilter()没有起到效果。

原因

查看源码得知:

  1. ImageView.setColorFilter()方法是作用在成员变量mDrawable上的,即xml内ImageView标签的android:src属性
  2. setBackgroundResource()方法是设置背景的,作用在ImageView的父类View的成员变量mBackground上的。

所以总结下来就是上述无效果的代码是因为设置到了两个对象上,才会导致最终没有效果。

修改

综上所述,修改方式有两种:

  1. 图片资源和着色都设置到ImageView背景上

    1
    2
    3
    4
    5
    Drawable drawable = ContextCompat.getDrawable(this, R.drawable.ic_setting);
    if (drawable != null) {
    drawable.setColorFilter(ContextCompat.getColor(this, R.color.colorPrimary), PorterDuff.Mode.SRC_IN);
    iv.setBackgroundDrawable(drawable);
    }
  2. 图片资源和着色都设置到ImageView内容上

    1
    2
    iv.setImageResource(R.drawable.ic_setting);
    iv.setColorFilter(ContextCompat.getColor(this, R.color.colorPrimary), PorterDuff.Mode.SRC_IN);

源码分析

setColorFilter()有3个重载方法,具体如下源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
* Sets a tinting option for the image.
*
* @param color Color tint to apply.
* @param mode How to apply the color. The standard mode is
* {@link PorterDuff.Mode#SRC_ATOP}
*
* @attr ref android.R.styleable#ImageView_tint
*/
public final void setColorFilter(int color, PorterDuff.Mode mode) {
setColorFilter(new PorterDuffColorFilter(color, mode));
}

/**
* Set a tinting option for the image. Assumes
* {@link PorterDuff.Mode#SRC_ATOP} blending mode.
*
* @param color Color tint to apply.
* @attr ref android.R.styleable#ImageView_tint
*/
@RemotableViewMethod
public final void setColorFilter(int color) {
setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
}

/**
* Apply an arbitrary colorfilter to the image.
*
* @param cf the colorfilter to apply (may be null)
*
* @see #getColorFilter()
*/
public void setColorFilter(ColorFilter cf) {
if (mColorFilter != cf) {
mColorFilter = cf;
mHasColorFilter = true;
mColorMod = true;
applyColorMod();
invalidate();
}
}

可以看到最终都调用到了 setColorFilter(ColorFilter cf)方法上。setColorFilter(ColorFilter cf)内部又会调用applyColorMod()。其代码如下,可以看到最总是调用到了mDrawable.setColorFilter(mColorFilter)上。

1
2
3
4
5
6
7
8
9
10
11
12
13
private void applyColorMod() {
// Only mutate and apply when modifications have occurred. This should
// not reset the mColorMod flag, since these filters need to be
// re-applied if the Drawable is changed.
if (mDrawable != null && mColorMod) {
mDrawable = mDrawable.mutate();
if (mHasColorFilter) {
mDrawable.setColorFilter(mColorFilter);
}
mDrawable.setXfermode(mXfermode);
mDrawable.setAlpha(mAlpha * mViewAlphaScale >> 8);
}
}

mDrawable通过查看源码内赋值的地方,可以确定为ImageView显示的内容(非背景)。因为源码内setImageBitmap、setImageDrawable、setImageResource、setImageURI、setImageIcon都是直接或间接调用了updateDrawable方法,其内部会将显示内容赋值给mDrawable。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
private void updateDrawable(Drawable d) {
if (d != mRecycleableBitmapDrawable && mRecycleableBitmapDrawable != null) {
mRecycleableBitmapDrawable.setBitmap(null);
}

boolean sameDrawable = false;

if (mDrawable != null) {
sameDrawable = mDrawable == d;
mDrawable.setCallback(null);
unscheduleDrawable(mDrawable);
if (!sCompatDrawableVisibilityDispatch && !sameDrawable && isAttachedToWindow()) {
mDrawable.setVisible(false, false);
}
}

//看这里哦
mDrawable = d;

if (d != null) {
d.setCallback(this);
d.setLayoutDirection(getLayoutDirection());
if (d.isStateful()) {
d.setState(getDrawableState());
}
if (!sameDrawable || sCompatDrawableVisibilityDispatch) {
final boolean visible = sCompatDrawableVisibilityDispatch
? getVisibility() == VISIBLE
: isAttachedToWindow() && getWindowVisibility() == VISIBLE && isShown();
d.setVisible(visible, true);
}
d.setLevel(mLevel);
mDrawableWidth = d.getIntrinsicWidth();
mDrawableHeight = d.getIntrinsicHeight();
applyImageTint();
applyColorMod();

configureBounds();
} else {
mDrawableWidth = mDrawableHeight = -1;
}
}
坚持原创技术分享,您的支持是对我最大的鼓励!