@act262
2017-04-08T03:17:18.000000Z
字数 1654
阅读 2123
Android
一个项目中很多地方公用了一个颜色值,然后有个地方会对这个控件的背景动态修改了,会出现其他引用这个颜色值的地方被跟随变化了,实际上这是不对的.
<color name="bg_toolbar">#222C57</color>
<android.support.v7.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="@54dp"android:background="@color/bg_toolbar"android:minHeight="?attr/actionBarSize" />
/*** 设置背景色的透明度** @param alpha 0~255,0完全透明,255完全不透明*/public void setBackgroundAlpha(@IntRange(from = 0, to = 255) int alpha) {if (currentAlpha != alpha) {getBackground().setAlpha(alpha);currentAlpha = alpha;}}
然后出现了问题,有时发现某个地方颜色竟然透明了(其他地方的颜色跟随这个变化了)
解决方案
在需要修改背景的控件初始化的时候重新设置一遍其 mutate后的Drawable,然后再修改Drawable属性
setBackground(getBackground().mutate());
从一个资源加载的地方找起,Resources
//Drawable loadDrawable(TypedValue value, int id, Theme theme){// 1.从缓存中找资源// 2.如果缓存中找到直接返回// 3.缓存中没有则是new一个,然后缓存下来}private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches, Theme theme, boolean usesTheme, long key, Drawable dr){}
这里会在加载时根据一定的情况从缓存中读写,所以没有一样的Drawable,每个Drawable都是唯一的,默认共享ConstantState(享元模式).
查看Drawable相关源码,
ConstantState所有相同一份资源都会共享其ConstantState,所以修改一个地方引用的Drawable就相当于修改了其他地方引用,使用mutate方法后生成一份新的ConstantState不再使用共享的ConstantState,即不会影响到其他的引用.
eg:使用color作为background对应的Drawable是ColorDrawable
public Drawable mutate() {if (!mMutated && super.mutate() == this) {// 说明重新赋值了一个ConstantState给他mColorState = new ColorState(mColorState);mMutated = true;}return this;}
调用mutate后再修改其属性就不会影响到公共的属性状态了.
在使用Drawable系列的时候要特别注意修改Drawable的属性引起其他引用这个Drawable的属性同时变化,尤其是我们常用的ColorDrawable,BitmapDrawable.
同理在ImageView中设置透明度setAlpha方法也会有这样的情况.
还有设置各种tint时也要注意.