1. 程式人生 > >Android 開發藝術探索筆記之六 -- Android 的 Drawable

Android 開發藝術探索筆記之六 -- Android 的 Drawable

整理一下,基本只作為 知識清單 使用

學習內容:

  • Drawable 的層次關係
  • Drawable 分類
  • 自定義 Drawable 的相關知識

Drawable 簡介

Drawable 表示的是一種可以在 canvas 上進行繪製的影象的 抽象概念。實際開發中,Drawable 常被用來作為 View 的背景使用。

優點:

  1. 使用簡單,比自定義 View 的成本低
  2. 非圖片型別的 Drawable 佔用空間較小,有利於減小 apk 的大小。

層次關係:

  1. Drawable 是一個抽象類,是所有 Drawable 物件的基類。
  2. 每個具體的 Drawable 都是它的子類,比如 ShapeDrawable,BitmapDrawable 等。

Drawable 內部寬 / 高

  1. 通過 getIntrinsicWidth 和 getIntrinsicHeight 兩個方法獲取。
  2. 並非所有 Drawable 都有內部寬/高(圖片形成的 Drawable 內部寬/高等同於圖片的寬/高,顏色形成的 Drawable 沒有內部寬/高的概念)
  3. Drawable 的內部寬/高不等同於它的大小,一般來說,Drawable 沒有大小概念,當作為 View 背景時,會被拉甚至 View 的同等大小。

Drawable 分類

1.BitmapDrawable

表示的就是一張圖片,可以直接引用原始的圖片,也可以通過 xml 方式描述它。

<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android" android:src="@[package:]drawable/drawable_resource" android:antialias=["true"|"false"] android:dither=["true"|"false"] android:filter=["true"|"false"] android:gravity=["top"|"bottom"|"left"|"right"|"center_vertical"|"fill_vertical"|"center_horizontal"|"fill_horizontal"|"center"|"fill"|"clip_vertical"|"clip_horizontal"]
android:mipMap=["true"|"false"] android:tileMode=["disabled"|"clamp"|"repeat"|"mirror"]>
</bitmap>

屬性說明:

  1. android:src:圖片的資源 ID
  2. android:antialias:抗鋸齒,犧牲清晰度使圖片平滑。建議開啟
  3. android:dither:抖動效果,當圖片畫素配置和手機螢幕的畫素配置不一致時,開啟此選項可以讓高質量圖片在低質量螢幕上還能保持較好的小時效果。建議開啟
  4. android:filter:過濾效果,圖片拉伸或壓縮時,開啟此選項可以保持較好的顯示效果。建立開啟
  5. android:gravity:當圖片小於容器的尺寸時,設定此選項對圖片進行定位,多個屬性值可以通過 “|” 來組合使用
  6. android:mipMap:紋理對映,預設值為 false,日常開發中不涉及此項
  7. android:tileMode:平鋪模式,預設為 disabled,關閉平鋪模式;clamp 表示圖片四周的畫素擴散到周圍區域;repeat 表示簡單的水平和垂直方向上的平鋪效果;mirror 表示一種水平和豎直方向上的鏡面投影效果;另外需要注意,當開啟平鋪模式後, gravity 屬性將被忽略。

2.ShapeDrawable

可以理解為通過顏色來構造的圖形,既可以是純色的圖形,也可以是具有漸變效果的圖形。

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape=["rectangle"|"oval"|"line"|"ring"]>
    <corners
        android:bottomLeftRadius="integer"
        android:bottomRightRadius="integer"
        android:radius="integer"
        android:topLeftRadius="integer"
        android:topRightRadius="integer" />

    <gradient
        android:angle="integer"
        android:centerColor="integer"
        android:centerX="integer"
        android:centerY="integer"
        android:endColor="color"
        android:gradientRadius="integer"
        android:startColor="color"
        android:type=["linear"|"radial"|"sweep"]
        android:useLevel=["false"|"false"] />

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

    <size
        andorid:width="integer"
        andorid:height="integer"/>

    <solid android:color="color" />

    <stroke
        android:width="integer"
        android:color="color"
        android:dashGap="integer"
        android:dashWidth="integer" />
</shape>

屬性說明:

  1. android:shape:表示圖形的形狀,有四種:rectangle矩形,oval橢圓,line橫線,ring圓環。
    1. 預設為矩形
    2. line 和 ring 必須通過 \ 指定線的寬度和顏色等資訊
    3. ring 有特殊的5個屬性:
      1. android:innerRadius:圓環內半徑,優先順序大於android:innerRadiusRatio
      2. android:thickness:圓環的厚度,優先順序大於 android:thicknessRatio
      3. android:innerRadiusRatio:內半徑佔整個 Drawable 寬度的比例
      4. android:thicknessRatio:厚度佔整個 Drawable 寬度的比例
      5. android:useLevel:一般都使用 false,除非當作 LevelListDrawable 來使用。
  2. \:表示 shape 的四個角的圓角角度,單位是 px,只適用於 矩形 shape。有如下 5 個屬性:
    1. android:radius:為四個角同時設定相同角度,優先順序低。
    2. andorid:topLeftRadius:左上角的角度
    3. andorid:topRightRadius:右上角的角度
    4. andorid:bottomLeftRadius:左下角的角度
    5. andorid:bottomRightRadius:右下角的角度
  3. \:與 \ 互斥,solid 表示純色填充,gradient 表示漸變效果,有以下屬性:
    1. android:angle:漸變的角度,預設為0,其值必須是 45 的倍數,0表示從左往右,90 表示 從上到下。
    2. android:centerX:漸變的中心橫座標
    3. android:centerY:漸變的中心縱座標
    4. android:startColor:漸變起始色
    5. android:centerColor:漸變的中間色
    6. android:endColor:漸變的結束色
    7. android:gradientRadius:漸變半徑,僅當 android:type=”radial” 時有效
    8. android:useLevel:一般為 false,當 Drawable 作為 StateListDrawable 使用時為 true
    9. android:type:漸變的類別,有 linear 線性漸變、radial 徑向漸變、sweep 掃描線漸變三種,預設為 線性漸變
  4. \:表示 純色填充,通過 android:color 指定 填充的顏色
  5. \:Shape 的描邊,有如下屬性
    1. android:width:描邊寬度
    2. android:color:描邊顏色
    3. android:dashWidth:組成虛線的線段的寬度
    4. android:dashGap:組成虛線的線段之間的間隔
  6. \:表示包含當前 Shape 的 View 的空白,有四個屬性, android:left、android:right、android:top、android:bottom。
  7. \:shape 的大小,有兩個屬性:android:width 和 android:height,分別表示 shape 的固有寬/高,但是作為 View 的背景時,仍會被拉伸或者縮小為 View 的大小

3.LayerDrawable

對應的 XML 標籤是 \,表示一種層次化的 Drawable 集合。一個 layer-list 可以包含多 個item,每一個 item 表示一個 Drawable。

Layer-list 有層次的概念,下面的 item 會覆蓋上面的 item,即會分層與疊加。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@[package:]drawable/drawable_resource"
        android:id="@[+][package:]id/resource_name"
        android:bottom="dimenison"
        android:left="dimenison"
        android:right="dimenison"
        android:top="dimenison" />

</layer-list>

4.StateListDrawable

對應於 \ 標籤,也是表示 drawable 集合,每個 Drawable 對應著 View 的一種狀態,這樣系統會根據 View 的狀態來選擇合適的 Drawable。

主要用於設定可單擊的 View 的背景。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" 
    android:constantSize=["true"|"false"]
    android:dither=["true"|"false"]
    android:variablePadding=["true"|"false"]>
    <item 
        android:drawable="@[package:]drawable/drawable_resource"
        android:state_pressed=["true"|"false"]
        android:state_foucused=["true"|"false"]
        android:state_hoverd=["true"|"false"]
        android:state_selected=["true"|"false"]
        android:state_checkable=["true"|"false"]
        android:state_checked=["true"|"false"]
        android:state_enabled=["true"|"false"]
        android:state_activated=["true"|"false"]
        android:state_window_focused=["true"|"false"] />
</selector>

相關屬性介紹:

  1. android:constantSize:固有大小是否不隨著其狀態的改變而改變,因為狀態的改變會導致 StateListDrawable 切換到具體的 Drawable,而不同的 Drawable 有不同的固有大小,true 表示 固有大小保持不變,此時它的固有大小是內部所有 Drawable 的固有大小的最大值。預設值為 false
  2. android:dither:是否開啟抖動效果。
  3. android:variablePadding:padding 是否隨著其狀態的改變而改變。類似 constantSize 屬性。
  4. 狀態相關
    1. android:state_pressed:按下狀態,此時按下尚未鬆開
    2. android:state_focused:獲取了焦點
    3. android:state_selected:使用者選擇了 view
    4. android:state_checked:使用者選中了 view
    5. android:state_enabled:view 當前處於可用狀態

5.LevelListDrawable

對應於 \ 標籤,同樣表示 Drawable 集合,集合中的每個 Drawable 都有一個 等級level 的概念,根據不同等級,切換對應的 Drawable。

每個 item 對應一個 Drawable,並且由 android:maxLevel 和 android:minLevel 指定對應的等級範圍。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/drawable_resource" 
          android:maxLevel="integer"
          android:minLevel="integer"/>
</selector>

6.TransitionDrawable

對應於 \ 標籤,用於實現兩個 Drawable 之間的淡入淡出的效果。

<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@[package:]drawable/drawable_resource"
        android:id="@[+][package:]id/resource_name"
        android:bottom="dimenison"
        android:left="dimenison"
        android:right="dimenison"
        android:top="dimenison"/>
</transition>

通過將 TransitionDrawable 設定為 view 的背景,通過view 的 startTransition 和 reverseTransition 方法實現淡入淡出的效果以及其逆過程。

7.InsetDrawable

對應於 \ 標籤,可以將其他 Drawable 內嵌到自己當中,並可以在四周留出一定的間距。當一個 View 希望自己的背景比自己的實際區域小的時候,可以採用 InsetDrawable 來實現。

<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/drawable_resource"
    android:insetBottom="dimension"
    android:insetLeft="dimension"
    android:insetRight="dimension"
    android:insetTop="dimension">
</inset>

8.ScaleDrawable

對應於 \ 標籤,根據自己的等級 level 將指定的 Drawable 縮放到一定比例。

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/drawable_resource"
    android:scaleGravity=["top"|"bottom"|"left"|"right"|"center_vertical"|"fill_vertical"|"center_horizontal"|"fill_horizontal"|"center"|"fill"|"clip_vertical"|"clip_horizontal"]
    android:scaleHeight="percentage"
    android:scaleWidth="percentage">
</scale>

定義的縮放比例越大,那麼內部 Drawable 看起來越小。

除了定義上述 Drawable,還需要設定等級。

ScaleDrawable scaleDrawable = (ScaleDrawable) imageView.getBackground();
caleDrawable.setLevel(1);

9.ClipDrawable

對應於 \ 標籤,根據自己當前等級 Level 來裁剪另一個 Drawable,裁剪方向可以通過 android:clipOrientation 和 android:gravity 共同控制。

<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:clipOrientation=["horizontal"|"vertical"]
    android:drawable="@drawable/drawable_resource"
    android:gravity=["top"|"bottom"|"left"|"right"|"center_vertical"|"fill_vertical"|"center_horizontal"|"fill_horizontal"|"center"|"fill"|"clip_vertical"|"clip_horizontal"]>
</clip>

仍需要在程式碼中設定 ClipDrawable 的等級。等級的範圍是 0~10000,0 表示 完全裁剪,10000 表示不裁剪。

ClipDrawable clipDrawable = (ClipDrawable) ivLevei.getBackground();
clipDrawable.setLevel(7000);

自定義 Drawable

通常下,沒有必要自定義 Drawable,因為自定義的 Drawable 無法在 xml 中使用。

核心方法:draw(),setAlpha(),setColorFilter(),sgetOpacity()。

當自定義的 Drawable 由固有大小時最好重寫 getInntrinsicWidth 和 getintrinsicHeight ,因為二者會影響到 view 的 wrap_content 佈局。

內部大小不等於 Drawable 的實際區域大小,Drawable 實際區域大小可以通過 getBounds 方法得到,一般個它的 View 的尺寸相同。