@act262
2017-04-08T03:17:18.000000Z
字数 1654
阅读 2026
Android
一个项目中很多地方公用了一个颜色值,然后有个地方会对这个控件的背景动态修改了,会出现其他引用这个颜色值的地方被跟随变化了,实际上这是不对的.
<color name="bg_toolbar">#222C57</color>
<android.support.v7.widget.Toolbar
android: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时也要注意.