为了账号安全,请及时绑定邮箱和手机立即绑定

Android-Drawable setColorFilter方法踩坑

标签:
Android

原创-转载请注明出处

Drawable mutations

有没有遇到过这样一种情况,我们要加载同一资源到两个ImageView,但需要给其中一个资源改变颜色或者透明度。如下面的代码

    ImageView imageView1 = (ImageView) view.findViewById(R.id.imageview);
    ImageView imageView2 = (ImageView) view.findViewById(R.id.imageview2);

    Drawable drawable = getResources().getDrawable(R.mipmap.ic_launcher);
    drawable.setColorFilter(Color.RED, PorterDuff.Mode.SRC_ATOP);
    imageView.setImageDrawable(drawable);

    Drawable drawable1 = getResources().getDrawable(R.mipmap.ic_launcher);
    imageView2.setImageDrawable(drawable1);

我们给imageView1设置ColorFilter改变一下图标的颜色,imageview2保持不变。这样会发生什么呢,看下面的图:

webp


这时候奇怪的事情发生了,两个ImageView都被改变了颜色。这是因为Drawable使用在Android系统中使用范围比较广,系统对此作了优化,同一资源的drawable共享一个状态,叫做ConstantState.例如,上面的R.mipmap.ic_launcher,每次新建一个drawable都是一个不同的drawable实例,但他们共享一个状态,这个状态中包含bitmap image,所以所有的R.mipmap.ic_launcher都共享一个bitmap,这就是两个ImageView都改变颜色原因。

Because drawables are used so extensively throughout the system, Android optimizes them when they are loaded from resources. For instance, every time you create a Button, a new drawable is loaded from the framework resources (android.R.drawable.btn_default). This means all buttons across all the apps use a different drawable instance as their background. However, all these drawables share a common state, called the "constant state." The content of this state varies according to the type of drawable you are using, but it usually contains all the properties that can be defined by a resource. In the case of a button, the constant state contains a bitmap image. This way, all buttons across all applications share the same bitmap, which saves a lot of memory.(摘抄自Android Developers Blog)。如下图所示

webp

但有没有办法解决呢,Drawable提供了一个mutate方法,我们来看下mutate方法的注释

Make this drawable mutable. This operation cannot be reversed. A mutable drawable is guaranteed to not share its state with any other drawable. This is especially useful when you need to modify properties of drawables loaded from resources. By default, all drawables instances loaded from the same resource share a common state; if you modify the state of one instance, all the other instances will receive the same modification. Calling this method on a mutable Drawable will have no effect.

mutate不知道怎么翻译合适,姑且叫做可变的吧。这个mutate方法使得这个drawable变成可变的,这个操作不可逆转。调用了mutate方法,使得该drawable不和其他drawable共享状态。
我们来看下这个mutate的实现,发现在Drawable源码中,mutate方法只是返回了他自身。那我们来看下drawable子类有没有对该方法重写。我们找到BitmapDrawable

     @Override
    public Drawable mutate() {        if (!mMutated && super.mutate() == this) {
            mBitmapState = new BitmapState(mBitmapState);
            mMutated = true;
        }        return this;
    }

如果没有调用过mutate方法,会新建一个BitmapState,再将mMutated置为true。这样相当于做了一次状态的拷贝,就不会与其他drawable共享状态了。
接下来我们修改下上面的代码

    ImageView imageView1 = (ImageView) view.findViewById(R.id.imageview);
    ImageView imageView2 = (ImageView) view.findViewById(R.id.imageview2);

    Drawable drawable = getResources().getDrawable(R.mipmap.ic_launcher).mutate();
    drawable.setColorFilter(Color.RED, PorterDuff.Mode.SRC_ATOP);
    imageView.setImageDrawable(drawable);

    Drawable drawable1 = getResources().getDrawable(R.mipmap.ic_launcher);
    imageView2.setImageDrawable(drawable1);

运行效果:

webp


这次两个ImageView不相同了.



作者:程序猿Jeffrey
链接:https://www.jianshu.com/p/ee969fab02b3


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消