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。敬請期待。