Drawable 是開發中常常用到的一個概念,咱們常常用它去設置 View 的背景,背景能夠一個顏色值,也能夠是一張資源圖片,還能夠是一個自定義的 Drawable等等。這篇文章就簡單說下 Drawable 與 View 的關係,同時結合代碼,簡要分析一下 Drawable 如何做用於 View。java
官方介紹android
A Drawable is a general abstraction for "something that can be drawn." Most often you will deal with Drawable as the type of resource retrieved for drawing things to the screen; the Drawable class provides a generic API for dealing with an underlying visual resource that may take a variety of forms. Unlike a
View
, a Drawable does not have any facility to receive events or otherwise interact with the user.git
簡單翻譯下:github
Drawable 是 「全部可繪製東西」 的一個抽象,大多數時候,咱們只須要把各類不一樣類型的資源做爲轉化爲 drawable,而後 View 會幫咱們把它渲染到屏幕上。Drawable 類提供了一個通用 API,用於解析轉化各類可視資源到 Canvas,跟 View 不同,Drawable 不能接受任何事件以及用戶交互。canvas
總而言之,Drawable 就是一個可繪製東西的抽象,相比 View,它更純粹,就是用來作繪製相關事情的,它處理不了用戶交互事件,也不須要處理,全部交互相關的事都是由 View 來完成,可是背景相關的事大均可以經過 Drawable 來完成。設計模式
通常的,咱們要爲 View 設置背景,可經過以下幾種方式:ide
經過 View 的 setBackgroundColor 方法能夠設置顏色爲 View 的背景。ui
button.setBackgroundColor(Color.YELLOW);
複製代碼
效果以下:spa
先用 xml 自定義一個圓角空心描邊矩形 shape翻譯
<shape android:shape="rectangle">
<corners android:radius="4dp"/>
<solid android:color="#fff"/>
<stroke android:color="#ef6f06" android:width="1dp"/>
</shape>
複製代碼
經過代碼進行設置
button.setBackgroundResource(R.drawable.bk_normal);
複製代碼
效果以下:
能夠看到,給 View 設置背景 drawable 很是簡單,具體經過以下的 API 實現背景設置:
可是設置的背景 Drawable 是如何在 View 上生效的,可能不少人沒去思考過這個問題,這裏簡單分析下。
Drawable 是一個抽象類,這裏經過它的的幾個抽象方法就能大概猜得出 Drawable 如何做用於 View,下面是 Drawable 的幾個抽象方法:
public abstract void draw(@NonNull Canvas canvas);
public abstract void setAlpha(@IntRange(from=0,to=255) int alpha);
public abstract void setColorFilter(@Nullable ColorFilter colorFilter);
public abstract @PixelFormat.Opacity int getOpacity();
複製代碼
能夠看到這裏有一個 draw 方法,而且參數中提供了 canvas 對象。
public abstract void draw(@NonNull Canvas canvas);
複製代碼
如今能夠想象一下,View 經過 setBackground 方法爲本身設置了一個 drawable 對象後,而 drawable 又有一個 draw 方法,那麼 View 繪製本身的背景時,直接調用 drawable 對象的的 draw 方法,這個 draw 方法須要一個 canvas 對象,這裏可直接把 View 的 Canvas 對象傳遞過去,那麼 Drawable 就能夠成功的把本身的繪製內容應用到 View 之上。
這個過程,至關於 View 把本身的背景繪製功能外包給了 Drawable 對象。
並且,這也是一種很是好的設計模式,View 負責測量本身大小,給本身指定位置,並繪製 View 前景 ,可是把本身的背景繪製外派給了更獨立的 drawable 去作,從而作到了讓本身更加輕量,如今 View 就成功的把背景繪製職責分配給了本身的 drawable 對象。
儘管上面只是想象,但事實上也確實如此。經過查看源碼,在 View 中有一個私有方法 drawBackground
,它的做用就是把 drawable 繪製在 canvas 上。
/** * Draws the background onto the specified canvas. * @param canvas Canvas on which to draw the background */
private void drawBackground(Canvas canvas) {
final Drawable background = mBackground;
if (background == null) {
return;
}
setBackgroundBounds();
//省略部分代碼
final int scrollX = mScrollX;
final int scrollY = mScrollY;
if ((scrollX | scrollY) == 0) {
//調用 drawable 本身的 draw 方法,從而將繪製的功能移交到 drawable 類
background.draw(canvas);
} else {
canvas.translate(scrollX, scrollY);
background.draw(canvas);
canvas.translate(-scrollX, -scrollY);
}
}
複製代碼
Drawable 是一個抽象的概念,只要理解了它跟 View 的關係,其實 Drawable 的想象力會很是大。經過自定義 Drawable,能夠在 Drawable 中完成各類繪製邏輯,自定義完成後,只須要讓 View 調用 setBackground() 方法,把自定義的 Drawable 傳遞進去,這樣就能夠方便把自定義 Drawable 和 View 關聯在一塊兒。
以前寫過一個轉菊花的 Loading 效果,就是用自定義 Drawable 實現的,目前已開源在 github,感興趣的去看看。
FlowerLoading: Android loading or progress view, just like iOS IndicatorView.
咕咚,Android 工程師,我的博客 gudong.name
本篇文章由一文多發平臺ArtiPub自動發佈