View繪制流程之drawable(一)

Drawable

Drawable,Bitmap檩坚,Canvas着撩,View之間的關(guān)系

以下純屬于個人理解,參考自文獻(xiàn)1匾委,文獻(xiàn)2拖叙,文獻(xiàn)2

Bitmap是一種像素存儲介質(zhì),圖像最終要保存下來要通過它剩檀。Canvas則是繪圖工具憋沿,提供了2D的繪圖方法旺芽,方便我們繪圖沪猴。View是一種容器,裝在Bitmap采章,將其呈現(xiàn)出來运嗜。Drawable:Android把可繪制的圖像抽象成了Drawable,封裝了一系列繪圖時需要做的工作(例如設(shè)定角度悯舟、長度担租、大小、顏色)抵怎,最后在draw()方法中用Canvas以及Bitmap繪制奋救。那么有了疑問既然Canvas能完成繪圖的工作和必要Drawable呢岭参?其實繪圖還需要Paint,來設(shè)置畫筆的顏色尝艘,尺寸等屬性演侯。Drawable相當(dāng)于一個框架,集合了繪圖的一些列工作(Paint背亥,Canvas秒际,Bitmap),封裝起來狡汉,方便開發(fā)者使用娄徊。

Drawable類型

Android內(nèi)置了如下幾種Drawable類型:ColorDrawable、GradientDrawable盾戴、BitmapDrawable寄锐、 NinePatchDrawable、InsetDrawable尖啡、ClipDrawable锐峭、ScaleDrawable、RotateDrawable可婶、AnimationDrawable沿癞、LayerDrawable、LevelListDrawable矛渴、StateListDrawable椎扬、TransitionDrawable

在實際的開發(fā)過程中,會把使用到的資源都放置在res/drawable目錄具温,AndroidStudio會把該目錄下的資源在項目R文件中生成相應(yīng)的id蚕涤。當(dāng)需要使用圖片資源的時候,可以使用@drawable標(biāo)志在xml中引用drawable資源铣猩,也可以在代碼中使用id引用這些drawable資源揖铜。

drawable是內(nèi)存共享的,也就是說不同地方使用同一個id达皿,指向的是同一個drawable資源天吓,具有相同的狀態(tài)。當(dāng)改變drawable資源的狀態(tài)峦椰,引用該資源的地方都會改變龄寞。

ColorDrawable

ColorDrawable 是最簡單的Drawable,它實際上是代表了單色可繪制區(qū)域汤功,它包裝了一種固定的顏色物邑,當(dāng)ColorDrawable被繪制到畫布的時候會使用顏色填充Paint,在畫布上繪制一塊單色的區(qū)域。
XML

<?xml version="1.0" encoding="utf-8"?>
<color xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@android:color/holo_blue_light">
</color>

在xml文件中使用color作為根節(jié)點來創(chuàng)建ColorDrawable色解,它只有一個android:color屬性茂嗓,通過它來決定ColorDrawable的顏色,Android并沒有提供修改這個顏色值的Api科阎,所以這個顏色一旦設(shè)置之后在抛,就不能直接修改了。

我們也可以通過java代碼來創(chuàng)建ColorDrawable對象萧恕。Android中使用一個int類型的數(shù)據(jù)表示顏色值刚梭,通常習(xí)慣使用十六進(jìn)制格式的數(shù)據(jù)表示顏色值。一個int類型包含四個字節(jié)票唆,分別代表顏色的4個組成部分:透明度(Alpha)朴读、紅(RED)、綠(GREEN)走趋、藍(lán)(BLUE)衅金,每個部分由一個字節(jié)(8個bit)表示,取值范圍為0~255簿煌。在xml中使用顏色時可以省略透明度(Alpha)部分氮唯,如#ff0000表示紅色。但是在代碼中必須要明確指出透明度(Alpha)代表的數(shù)據(jù)姨伟,如果省略了就表示完全透明的顏色惩琉,例如0xFFFF0000表示紅色,而0xFF0000雖然也表示紅色夺荒,但它卻是完全透明的瞒渠,也就是說當(dāng)繪制到畫布上時,看不出有任何效果技扼。
java

ColorDrawable drawable = new ColorDrawable(0xffff0000);

GradientDrawable

GradientDrawable 表示一個漸變區(qū)域伍玖,可以實現(xiàn)線性漸變、發(fā)散漸變和平鋪漸變效果剿吻,在Android中可以使用GradientDrawable表示很多復(fù)雜而又絢麗的界面效果窍箍。
在xml文件中使用shape作為根節(jié)點來創(chuàng)建GradientDrawable,它包含很多屬性和子節(jié)點:
shape屬性是形狀定義丽旅,通過android:shape屬性指定:

  • rectangle: 矩形椰棘,默認(rèn)的形狀,可以畫出直角矩形魔招、圓角矩形晰搀、弧形等
  • oval: 橢圓形五辽,用得比較多的是畫正圓
  • line: 線形办斑,可以畫實線和虛線
  • ring: 環(huán)形,可以畫環(huán)形進(jìn)度條

shape還有一些特定場合的屬性,適用于android:shape屬性指定為ring時生效:

  • android:innerRadius 內(nèi)環(huán)的半徑
  • android:innerRadiusRatio 浮點型乡翅,以環(huán)的寬度比率來表示內(nèi)環(huán)的半徑鳞疲,默認(rèn)為3,表示內(nèi)環(huán)半徑為環(huán)的寬度除以3蠕蚜,該值會被android:innerRadius覆蓋
  • android:thickness 環(huán)的厚度
  • android:thicknessRatio 浮點型尚洽,以環(huán)的寬度比率來表示環(huán)的厚度,默認(rèn)為9靶累,表示環(huán)的厚度為環(huán)的寬度除以9腺毫,該值會被android:thickness覆蓋
  • android:useLevel 一般為false,否則可能環(huán)形無法顯示挣柬,只有作為LevelListDrawable使用時才設(shè)為true

子節(jié)點有:

  • solid: 設(shè)置形狀填充的顏色潮酒,只有android:color一個屬性

    android:color 填充的顏色

  • padding: 設(shè)置內(nèi)容與形狀邊界的內(nèi)間距,可分別設(shè)置左右上下的距離

    1. android:left 左內(nèi)間距
    2. android:right 右內(nèi)間距
    3. android:top 上內(nèi)間距
    4. android:bottom 下內(nèi)間距
  • gradient: 設(shè)置形狀的漸變顏色邪蛔,可以是線性漸變急黎、輻射漸變、掃描性漸變

    1. android:type 漸變的類型
      • linear 線性漸變侧到,默認(rèn)的漸變類型
      • radial 放射漸變勃教,設(shè)置該項時,android:gradientRadius也必須設(shè)置
      • sweep 掃描性漸變
    2. android:startColor 漸變開始的顏色
    3. android:endColor 漸變結(jié)束的顏色
    4. android:centerColor 漸變中間的顏色
    5. android:angle 漸變的角度匠抗,線性漸變時才有效故源,必須是45的倍數(shù),0表示從左到右汞贸,90表示從下到上
    6. android:centerX 漸變中心的相對X坐標(biāo)心软,放射漸變時才有效,在0.0到1.0之間著蛙,默認(rèn)為0.5删铃,表示在正中間
    7. android:centerY 漸變中心的相對X坐標(biāo),放射漸變時才有效踏堡,在0.0到1.0之間猎唁,默認(rèn)為0.5,表示在正中間
    8. android:gradientRadius 漸變的半徑顷蟆,只有漸變類型為radial時才使用
    9. android:useLevel 如果為true诫隅,則可在LevelListDrawable中使用
  • corners: 設(shè)置圓角,只適用于rectangle類型帐偎,可分別設(shè)置四個角不同半徑的圓角逐纬,當(dāng)設(shè)置的圓角半徑很大時,比如200dp削樊,就可變成弧形邊了

    1. android:radius 圓角半徑豁生,會被下面每個特定的圓角屬性重寫
    2. android:topLeftRadius 左上角的半徑
    3. android:topRightRadius 右上角的半徑
    4. android:bottomLeftRadius 左下角的半徑
    5. android:bottomRightRadius 右下角的半徑
  • stroke: 設(shè)置描邊兔毒,可描成實線或虛線。

    1. android:color 描邊的顏色
    2. android:width 描邊的寬度
    3. android:dashWidth 設(shè)置虛線時的橫線長度
    4. android:dashGap 設(shè)置虛線時的橫線之間的距離
  • size: 設(shè)置形狀默認(rèn)的大小甸箱,可設(shè)置寬度和高度

    1. android:width 寬度
    2. android:height 高度

實例XML:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <!-- shape可以定義四種形狀的drawable,矩形,橢圓形,線性,環(huán)形.默認(rèn)矩形-->
    <!--指定形狀的填充色,唯一屬性color-->
    <solid android:color="@android:color/holo_blue_light"/>

    <gradient
        android:type="linear"
        android:startColor="#E3F2FD"
        android:centerColor="#90CAF9"
        android:endColor="#0D47A1"
        android:angle="0"/>
    <!-- 設(shè)置內(nèi)邊距-->
    <padding
        android:bottom="12dp"
        android:left="12dp"
        android:right="12dp"
        android:top="12dp"/>
    <!-- corners設(shè)置圓角育叁,只適用于rectangle -->
    <corners android:radius="200dp"/>
    <!-- stroke設(shè)置drawable邊框
         width設(shè)置變寬寬度
         color設(shè)置邊框顏色
         dashGap設(shè)置虛線段的間隔
         dashWidth設(shè)置虛線段的長度-->
    <stroke
        android:width="2dp"
        android:color="@android:color/darker_gray"
        android:dashGap="4dp"
        android:dashWidth="4dp"/>
</shape>

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval" >
    <!-- android:gradientRadius 漸變的半徑,只有漸變類型為radial時才使用 -->
    <gradient
        android:type="radial"
        android:startColor="@android:color/holo_blue_light"
        android:endColor="@android:color/holo_red_light"
        android:centerColor="@android:color/holo_green_light"
        android:gradientRadius="50dp"
        android:centerX="1"
        android:centerY="0.8"
        />

    <padding
        android:bottom="4dp"
        android:top="4dp"
        android:right="4dp"
        android:left="4dp"/>

    <size
        android:width="60dp"
        android:height="60dp"/>
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="line">
    <!-- line主要用于畫分割線芍殖,是通過stroke和size特性組合 -->

    <!-- 實際顯示的線 -->
    <stroke
        android:width="1dp"
        android:color="@android:color/black"
        android:dashGap="3dp"
        android:dashWidth="8dp"/>

    <!-- 形狀的高度-->
    <size
        android:height="4dp"/>

    <!-- 這里需要注意:
         只能夠畫水平線;
         線的高度由stroke節(jié)點的android:width屬性指定;
         形狀的高度由size節(jié)點的android:height屬性指定,
         其值必須大于stroke節(jié)點的android:width的,
         否則線將無法顯示;
         線在形狀中時居中的;
         引用虛線的view需要添加屬性android:layerType豪嗽,
         值設(shè)為"software",否則顯示不了虛線豌骏。
         -->
</shape>

當(dāng)android:shape屬性制定為ring時龟梦,在shape跟節(jié)點中有一些特定的屬性生效:

  • android:innerRadius 內(nèi)環(huán)的半徑
  • android:innerRadiusRatio 浮點型,以環(huán)的寬度比率來表示內(nèi)環(huán)的半徑窃躲,默認(rèn)為3变秦,表示內(nèi)環(huán)半徑為環(huán)的寬度除以3,該值會被android:innerRadius覆蓋
  • android:thickness 環(huán)的厚度
  • android:thicknessRatio 浮點型框舔,以環(huán)的寬度比率來表示環(huán)的厚度蹦玫,默認(rèn)為9,表示環(huán)的厚度為環(huán)的寬度除以9刘绣,該值會被android:thickness覆蓋
  • android:useLevel 一般為false樱溉,否則可能環(huán)形無法顯示,只有作為LevelListDrawable使用時才設(shè)為true
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:innerRadiusRatio="4"
       android:thicknessRatio="5"
       android:shape="ring"
       android:useLevel="false">
    <!--環(huán)形的寬度是指環(huán)形drawable外面矩形的寬度,
        環(huán)形的厚度指的是外徑減去內(nèi)徑的大小-->
    <gradient
        android:centerColor="@android:color/holo_green_light"
        android:endColor="@android:color/holo_red_light"
        android:startColor="@android:color/holo_blue_light"
        android:type="sweep"/>
    <size
        android:width="60dp"
        android:height="60dp"/>
</shape>

效果圖:

TestDrawable.png

細(xì)說Drawable和View之間的關(guān)系

每一個View包括其子類都有一個drawable成員變量纬凤。在View.java中有一個Drawable作為背景福贞。
其實改變View圖形顯示的2D繪畫有兩種方式:

  • 調(diào)用 View 及其子類提供的方法如 View:setBackground(Drawable)ImageView:setImageBitmap(Bitmap)停士, 這些方法直接或間接設(shè)置相應(yīng)類中的 Drawable 私有成員挖帘。
  • 繼承 View 并重載 onDraw(Canvas),回調(diào)中得到畫布 Canvas恋技,調(diào)用其一系列基本圖形的繪畫 draw 方法操作其 Bitmap 中的像素數(shù)據(jù)拇舀。

雖然第二種情況看似和drawable無關(guān),其實在View.java中的draw()方法調(diào)用了drawable.draw(canvas)將背景繪制:

public class View {
  ...
  private Drawable mBackground; // 背景
  ...

  public void draw(Canvas canvas) {
    ...
    // Step 1, draw the background, if needed
    if (!dirtyOpaque) {
      drawBackground(canvas);
    }
    ...
  }

  private void drawBackground(Canvas canvas) {
    final Drawable background = mBackground;
    ...
    background.draw(canvas);
    ...
  }
}

參考資料蜻底,資料1骄崩,資料2

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市薄辅,隨后出現(xiàn)的幾起案子要拂,更是在濱河造成了極大的恐慌,老刑警劉巖站楚,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件脱惰,死亡現(xiàn)場離奇詭異,居然都是意外死亡窿春,警方通過查閱死者的電腦和手機拉一,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進(jìn)店門采盒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人舅踪,你說我怎么就攤上這事纽甘×悸” “怎么了抽碌?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長决瞳。 經(jīng)常有香客問我货徙,道長,這世上最難降的妖魔是什么皮胡? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任痴颊,我火速辦了婚禮,結(jié)果婚禮上屡贺,老公的妹妹穿的比我還像新娘蠢棱。我一直安慰自己,他們只是感情好甩栈,可當(dāng)我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布泻仙。 她就那樣靜靜地躺著,像睡著了一般量没。 火紅的嫁衣襯著肌膚如雪玉转。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天殴蹄,我揣著相機與錄音究抓,去河邊找鬼。 笑死袭灯,一個胖子當(dāng)著我的面吹牛刺下,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播稽荧,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼怠李,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蛤克?” 一聲冷哼從身側(cè)響起捺癞,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎构挤,沒想到半個月后髓介,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡筋现,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年唐础,在試婚紗的時候發(fā)現(xiàn)自己被綠了箱歧。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡一膨,死狀恐怖呀邢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情豹绪,我是刑警寧澤价淌,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站瞒津,受9級特大地震影響蝉衣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜巷蚪,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一病毡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧屁柏,春花似錦啦膜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至似嗤,卻和暖如春啸臀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背烁落。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工乘粒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人伤塌。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓灯萍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親每聪。 傳聞我的和親對象是個殘疾皇子旦棉,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,665評論 2 354

推薦閱讀更多精彩內(nèi)容