Android Drawable 簡析

Photo by Patrick Tomasso on Unsplash

Drawable 是開發中常常用到的一個概念,咱們常常用它去設置 View 的背景,背景能夠一個顏色值,也能夠是一張資源圖片,還能夠是一個自定義的 Drawable等等。這篇文章就簡單說下 Drawable 與 View 的關係,同時結合代碼,簡要分析一下 Drawable 如何做用於 View。java

Drawable 介紹

官方介紹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 設置背景
  • 經過自定義的 shape 設置背景

用顏色設置背景

經過 View 的 setBackgroundColor 方法能夠設置顏色爲 View 的背景。ui

button.setBackgroundColor(Color.YELLOW);
複製代碼

效果以下:spa

image

用自定義的 shape 設置背景

先用 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);
複製代碼

效果以下:

image

能夠看到,給 View 設置背景 drawable 很是簡單,具體經過以下的 API 實現背景設置:

  • setBackgroundColor(@ColorInt int color)
  • setBackgroundResource(@DrawableRes int resid)
  • setBackground(Drawable background)

可是設置的背景 Drawable 是如何在 View 上生效的,可能不少人沒去思考過這個問題,這裏簡單分析下。

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 的關係

  • View 是皮,它是一個具體的東西,看得見摸得着,由於它本身能夠測量本身打消、指定本身位置,還能接受 onTouch 事件從而處理用戶交互。
  • Drawable 是毛,它能夠不存在,由於 View 徹底能夠在本身的 onDraw 時機中,本身把本身繪製了,無需把繪製進行外包。
  • 可是 Drawable 更專業,更獨立,它提供了一整套豐富的背景 Drawable 機制,它有豐富的實現類,能夠提供給 View 進行方便的背景設置,對 View 來講 drawable 提供的那些實現類開箱即用,還能夠減小本身的職能,節省本身的維護開銷,何樂而不爲。

總結

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自動發佈

相關文章
相關標籤/搜索