ColorDrawable是Drawable子类中最简单的,表明一种颜色图。 在代码中使用是很是简单的。通常对于纯色背景均可以使用ColorDrawable。android
<?xml version="1.0" encoding="utf-8"?>
<color
xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#0000ff">
</color>
这样就定义了一个纯蓝色的背景
复制代码
而后就能够在Java代码中或者xml中使用canvas
Drawable d = getResources().getDrawable(R.drawable.color_drawable);
Log.i(TAG, d.getClass().getSimpleName());//输出ColorDrawable
在xml中,就是好比某个组件的background之类的属性就能够把资源引用加上去,系统就会加载该资源
复制代码
float[] array = {0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0};//颜色矩阵计算,从蓝色转变为红色
d.setColorFilter(new ColorMatrixColorFilter(array));
parent.setBackground(d);//从新设置背景色
复制代码
执行上述代码以后,发现颜色没变,仍是蓝色!WTF?Drawable源码里面明明写的是经过setColorFilter就能够改变颜色啊!那咱们要使用ColorDrawable改变颜色怎么办?bash
parent.setBackground(new ColorDrawable(Color.RED));//成功变成红色
复制代码
显然,新建立一个ColorDrawable固然没问题,可是为何setColorFilter没有用呢?ide
//ColorDrawable开头的注释内容
A specialized Drawable that fills the Canvas with a specified color.
Note that a ColorDrawable ignores the ColorFilter.//会忽略ColorFilter
复制代码
原来是这样子,它会忽略ColorFilter的值,那么究竟是在哪里处理的?由于ColorFilter是设置在Paint上的,因此咱们看一会儿类的draw方法,可能会有什么发现。源码分析
public void draw(Canvas canvas) {
// 获取ColorFilter
final ColorFilter colorFilter = mPaint.getColorFilter();
// 判断使用的颜色透明度是否为0,若是为0,则不必绘制背景了
// 这里须要注意,若是动态设置颜色的时候没有明确透明度,那么这里就是按照24位RGB来计算的,最后就是0!!!
if ((mColorState.mUseColor >>> 24) != 0 || colorFilter != null || mTintFilter != null) {
if (colorFilter == null) {
mPaint.setColorFilter(mTintFilter);
}
// 关键点在这里啊,从新设置了颜色值,这样就和ColorFilter无关了
mPaint.setColor(mColorState.mUseColor);
// 能够看到,ColorDrawable是按照矩形绘制的
canvas.drawRect(getBounds(), mPaint);
// Restore original color filter.
// 再把ColorFilter保存回来
mPaint.setColorFilter(colorFilter);
}
}
复制代码
到这里,咱们就知道对于ColorDrawable为何设置ColorFilter无效了。ui
int mBaseColor; // 基础颜色,和透明度独立
int mUseColor; // 会被透明度影响的基础颜色
复制代码
刚才咱们在draw方法里面用到的也是mUseColor,所以,咱们能够这样理解: mBaseColor是保存了set后的颜色 mUseColor是保存每次变化后的颜色 为何这么说呢?由于从源码中搜索能够看出,mBaseColor只有在setColor和updateFromTypedArray中才有更新this
当颜色不一致时才设置并重绘自身,所以能够经过setColor的方式改变颜色
public void setColor(@ColorInt int color) {
if (mColorState.mBaseColor != color || mColorState.mUseColor != color) {
mColorState.mBaseColor = mColorState.mUseColor = color;
invalidateSelf();
}
}
从xml中获取属性值
state.mBaseColor = a.getColor(R.styleable.ColorDrawable_color, state.mBaseColor);
复制代码
那么改变透明度就表示在mUseColor上面作动做么?spa
public void setAlpha(int alpha) {
alpha += alpha >> 7; // make it 0..256
final int baseAlpha = mColorState.mBaseColor >>> 24;//无符号右移,因此前24位都是0,最后8位是透明度
final int useAlpha = baseAlpha * alpha >> 8;
final int useColor = (mColorState.mBaseColor << 8 >>> 8) | (useAlpha << 24);
// 先左移8位去掉8位透明度,再无符号右移8位。
// 前8位0,后24为RGB颜色,再或透明度左移24位,最后获得新的32位ARGB颜色
if (mColorState.mUseColor != useColor) {
mColorState.mUseColor = useColor;
invalidateSelf();
}
}
复制代码
这么一大段左右移运算到底在干啥?为啥不能简单点?code
useColor & 0xFFFFFF | alpha << 24//这样不行么?
复制代码
说实话。。我没看懂透明度那部分为何要这么计算。。Google的工程师仍是天资聪颖 可是咱们也能够看到,全部的改变都是在mUserColor上进行,mBaseColor是一个基准颜色。xml
private boolean mMutated;//保存是否改变过的布尔值
public Drawable mutate() {
// 若是没有改变过,而且是同一个Drawable(super.mutate方法直接返回this)
if (!mMutated && super.mutate() == this) {
// 能够看到直接新建了一个ColorState,这样就不和其余ColorDrawable共享状态,所以不会相互影响,至关于深拷贝
mColorState = new ColorState(mColorState);
// 标记已改变
mMutated = true;
}
// mColorState是成员变量,所以this是一个已经改变后的ColorDrawable
return this;
}
复制代码
public void clearMutated() {
super.clearMutated();
mMutated = false;
}
// 能够看到该方法是能够清除标记位的,可是实际因为Hide,是没法调用的。因此一旦mutate调用了以后,就没法回头了哦。
复制代码
@Override
public Drawable newDrawable() {
return new ColorDrawable(this, null);
}
@Override
public Drawable newDrawable(Resources res) {
return new ColorDrawable(this, res);
}
// 这个this指代的就是ColorState,由于该方法是在ColorState类中定义的。
复制代码
那么在Java代码中,就可使用
d.getConstantState().newDrawable();
// 就能够建立一个和当前状态如出一辙的ColorDrawable对象,可是他们仍是共享一个ColorState哦。
复制代码
对于最简单的ColorDrawable须要了解的就这么多了。下一节将讨论比ColorDrawable稍微复杂一点的ShapeDrawable。敬请期待。