Android中常用的Drawable

q3202dasz 8年前發布 | 7K 次閱讀 安卓開發 Android開發 移動開發

前言

 

  • 本文的目錄結構

    • 前言
    • Drawable簡介
    • Drawable分類
      • BitmapDrawable
      • NinePatchDrawable
      • ShapeDrawable
      • LayerDrawable
      • StateListDrawable
      • LevelListDrawable
      • TransitionDrawable
      • InsetDrawable
      • ScaleDrawable
      • ClipDrawable
      </li>
    • 自定義Drawable
    • </ul> </li> </ul>

      Drawable簡介

      • Drawable表示的是一種可以在Canvas上進行繪制的抽象的概,可以是純顏色,也可以是圖片等。

      • Drawable一般是通過XML來定義,當然也可以通過代碼來創建。

      • Drawable類是抽象類,它是所有Drawable的基類。

      • Drawable的 getIntrinsicWidth() 和 getIntrinsicHeight() 獲取其內部寬/高。并不是所有Drawable都有內部寬/高。圖片所形成的Drawable的內部寬/高就是圖片的寬/高。顏色所形成的Drawable就沒有內部寬/高的概念了。

      • Drawable是沒有大小概念的,當用作View的背景時,會被拉伸至View的同等大小。

      • Drawable的使用范圍很單一:一是作為ImageView中的圖像顯示,二是作為View的背景。

      Drawable分類

      BitmapDrawable

      • 對應 <bitmap> 標簽,幾乎是最簡單的Drawable,表示一張圖片。

      • 在實際開發中,我們可直接引用原始的圖片,也可通過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]" />
      • android:src :圖片的資源id。

      • android:antialias :是否開啟圖片抗鋸齒。開啟后會讓圖片變得平滑,同時也會一定程度上降低圖片的清晰度。

      • android:dither :是否開啟抖動效果。開啟后可讓高質量的圖片在低質量的屏幕上能保持較好的顯示效果。

      • android:filter :是否開啟過濾效果。當圖片尺寸被拉伸或壓縮時,開啟過濾效果可保持較好的顯示效果。

      • android:gravity :當圖片小于容器的尺寸時,設置此屬性對圖片進行定位。此屬性的可選項較多,也可用 | 來組合使用。

      可選項 含義
      top 將圖片放在容器的頂部,不改變其大小。
      bottom 將圖片放在容器的底部,不改變其大小。
      left 將圖片放在容器的左部,不改變其大小。
      right 將圖片放在容器的右部,不改變其大小。
      center_vertical 使圖片豎直居中,不改變其大小。
      center_horizontal 使圖片水平居中,不改變其大小。
      fill_vertical 圖片豎直方向填充容器
      fill_horizontal 圖片水平方向填充容器
      center 使圖片居中,不改變其大小。
      fill 圖片填充容器,默認值。
      clip_vertical 豎直方向的裁剪。
      clip_horizontal 水平方向的裁剪。
      • android:mipMap :是否開啟紋理映射。

      • android:tileMode :平鋪模式。

      可選項 含義
      disabled 默認值,關閉平鋪模式。
      clamp 圖片四周的像素會擴展到周圍區域。
      repeat 簡單的水平和豎直方向上的平鋪效果。
      mirror 在水平和豎直方向上的鏡面投影效果。

      NinePatchDrawable

      • 表示一張 .9 格式的圖片。 .9 圖片可自動地根據所需的寬/高進行相應的縮放并保證不失真。

      • 在實際使用中直接引用 .9 圖片,也可以通過XML來描述它。

      <?xml version="1.0" encoding="utf-8"?>
      <nine-patch
          xmlns:android="http://schemas.android.com/apk/res/android"
          android:src="@[package:]drawable/drawable_resource"
          android:dither="[true | false]" />
      • android:src :圖片的資源id。

      • android:dither :是否開啟抖動效果。開啟后可讓高質量的圖片在低質量的屏幕上能保持較好的顯示效果。

      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:radius="integer"
              android:topLeftRaidus="integer"
              android:topRightRaidus="integer"
              android:bottomLeftRaidus="integer"
              android:bottomRightRaidus="integer" />
          <gradient
              android:angle="integer"
              android:centerX="integer"
              android:centerY="integer"
              android:centerColor="color"
              android:endColor="color"
              android:gradientRadius="integer"
              android:startColor="color"
              android:type="[linear | radial | sweep]"
              android:useLevel="[true | false]" />
          <padding
              android:left="integer"
              android:top="integer"
              android:right="integer"
              android:bottom="integer" />
          <size
              android:width="integer"
              android:height="integer" />
          <solid
              android:color="color" />
          <stroke
              android:width="integer"
              android:color="color"
              android:dashWidth="integer"
              android:dashGap="integer" />
      • android:shape :圖形的形狀,可選有 rectangle(矩形)、oval(橢圓)、line(橫線)和ring(圓環) 。默認是rectangle。注意line和ring必須通過 <stroke> 標簽來指定線的寬度和顏色等信息,否則無法達到預期的顯示效果。

      • android:shape="ring" 有5個特殊屬性。

      屬性 描述
      android:innerRadius 圓環的內半徑。<Br>會覆蓋android:innerRadiusRatio。
      android:innerRadiusRatio 內半徑占整個Drawable寬度的比例。
      默認為9,若為n,則內半徑 = 寬度 / n。
      android:thickness 圓環的厚度。即外半徑減去內半徑的大小。<Br>會覆蓋android:thicknessRatio
      android:thicknessRatio 厚度占整個Drawable寬度的比例。
      默認為3,若為n,則厚度 = 寬度 / n。
      android:useLevel 常為false,除非它被當做是LevelListDrawable。
      • <corners> :表示shape的四個圓角的角度,只適用于矩形。

        1. android:radius :為四個角同事設定相同的角度。優先級比以下4個屬性要低。
        2. android:topLeftRadius :左上角的角度。
        3. android:topRightRadius :右上角的角度。
        4. android:bottomLeftRadius :左下角的角度。
        5. android:bottomRightRadius :右下角的角度。
      • <solid> :純色填充,通過 android:color 指定填充的顏色。

      • <gradient> :漸變效果。與 <solid> 純色填充是互相排斥的。

        1. android:angle :漸變的角度。默認為0,其值必須為45的倍數。此角度會影響漸變的方向,0表示從左到右,90表示從下到上。
        2. android:centerX :漸變的中心點的X坐標。
        3. android:centerY :漸變的中心點的Y坐標。
        4. android:startColor :漸變的起始色。
        5. android:centerColor :漸變的中間色。
        6. android:endColor :漸變的結束色。
        7. android:gradient :漸變半徑。僅當 android:type="radial" 時有效。
        8. android:useLevel :一般為false,當Drawable作為StateListDrawable時為true。
        9. android:type :漸變的類別。有linear(線性漸變)、radial(徑向漸變)、sweep(掃描線漸變),默認為linear。
      • <stroke> :描邊。

        1. android:width :描邊的寬度。
        2. android:color :描邊的顏色。
        3. android:dashWidth :虛線的寬度。
        4. android:dashGap :虛線之間的間隔。
      • <padding> :空白。有 top 等四個屬性。

      • <size> :大小。其 android:width 和 android:height 分別設定shape的寬/高。注意,這個表示的是shape的固有大小,但并不是其最終大小。

      LayerDrawable

      • 對應 <layer-list> 標簽,表示一種層次化的Drawable集合,通過將不同的Drawable放置在不同的層上面從而達到一種疊加后的效果。
      <?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:top="dimension"
              android:right="dimension"
              android:bottom="dimension"
              android:left="dimension" />
          <!-- 其他item -->
      </layer-list>
      • 一個layer-list可包含多個item,每個item表示一個Drawable。可在 android:drawable 中引用一個現有的Drawable資源,也可在 <item> 中自定義Drawable。

      • 默認情況下,layer-list中的所有Drawable都會被縮放至View的大小。可設置Drawable相對于View的上下左右偏移量。另外對于bitmap,需要使用其 android:gravity 來控制圖片的顯示效果。

      • layer-list有層次的概念, 下面的item會覆蓋上面的item 。通過合理的分層,可實現一些特殊的疊加效果。

      • 利用layer-list實現一個文本輸入框。

        <?xml version="1.0" encoding="utf-8"?>
          <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
              <item>
                  <shape android:shape="rectangle">
                      <solid android:color="#0ac39e" />
                  </shape>
              </item>
              <item android:bottom="6dp">
                  <shape android:shape="rectangle">
                      <solid android:color="#ffffff" />
                  </shape>
              </item>
              <item
                  android:bottom="1dp"
                  android:left="1dp"
                  android:right="1dp">
                  <shape android:shape="rectangle">
                      <solid android:color="#ffffff" />
                  </shape>
              </item>
          </layer-list>

        layer-list背景的輸入框

      StateListDrawable

      • 對應 <selector> 標簽,表示一個Drawable的集合。 每個Drawable對應著View的一種狀態 ,系統會根據View的狀態來選擇合適的Drawable。
      <?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_focused="[true | false]"
              android:state_hovered="[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]" />
          <!-- 其他item -->
      </selector>
      • android:constantSize :StateListDrawable的固有大小是否不隨著其狀態的改變而改變。默認為false,即隨著狀態的改變而改變大小。若為true,則表示其內部所有Drawable的固有大小的最大值。

      • android:dither :是否開啟抖動效果。

      • android:variblePadding :StateListDrawable的padding是否隨著其狀態的改變而改變。默認為false,表示其內部所有Drawable的padding的最大值。若為true,表示會隨著狀態的改變而改變。

      • <item> :表示某種狀態下的一個具體的Drawable。用 android:drawable 指定一個現有Drawable的資源id,剩下的屬性表示的是View的各種狀態。

      狀態 含義
      android:state_pressed 表示按下狀態。
      android:state_focused 表示已經獲取了焦點。
      android:state_selected 表示用戶選擇了View。
      android:state_checked 表示用戶選中了View。<Br>適用于CheckBox這類在選中和非選中狀態之間進行切換的View。
      android:state_enabled 表示View當前處于可用狀態。
      • 系統會按照從上到下的順序查找,直至查找到第一條匹配的item。一般來說,默認的item都應該放在selector的最后一條,并且不附帶任何的狀態。

      LevelListDrawable

      • 對應 <level-list> 標簽,表示一個Drawable集合,集合中的每個Drawable都有一個等級的概念。根據不同的等級,LevelListDrawable會切換為對應的Drawable。
      <?xml version="1.0" encoding="utf-8"?>
      <level-list xmlns:android="http://schemas.android.com/apk/res/android">
          <item
              android:drawable="@[package:]drawable/drawable_resource"
              android:maxLevel="integer"
              android:minLevel="integer" />
          <!-- 其他item -->
      </level-list>
      • 每個item表示一個Drawable,并且有對應的等級范圍,在 maxLevel 和 minLevel 之間。取值范圍為0~10000,默認為0。

      • 若作為View背景時,可通過Drawable的 setLevel() 來設置不同的等級來切換具體的Drawable。若作為ImageView的前景,可通過ImageView的 setImageLevel() 來切換。

      TransitionDrawable

      • 對應于 <transition> 標簽,用于實現兩個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:top="dimension"
              android:right="dimension"
              android:bottom="dimension"
              android:left="dimension" />
          <!-- 另一個item,注意transition只包含兩個item -->
      </transition>
      • 常將TransitionDrawable作為View的背景,再調用它的 startTransition() 和 reverseTransition() 來實現淡入淡出效果以及它的逆過程。
      ImageView ivBg = (ImageView) findViewById(R.id.iv_bg);
      TransitionDrawable drawable = (TransitionDrawable) ivBg.getBackground();
      drawable.startTransition(1000);

      InsetDrawable

      • 對應 <inset> 標簽,可將其他Drawable內嵌到自己當中,并可在四周留出一定的間距。
      <?xml version="1.0" encoding="utf-8"?>
      <inset 
          xmlns:android="http://schemas.android.com/apk/res/android"
          android:drawable="@[package:]drawable/drawable_resource"
          android:inset="dimension"
          android:insetTop="dimension"
          android:insetRight="dimension"
          android:insetBottom="dimension"
          android:insetLeft="dimension" />
      • 當一個View希望自己的背景比自己的實際區域小的時候,可采用InsetDrawable,并通過 inset* 屬性來設置留白。

      ScaleDrawable

      • 對應 <scale> 標簽,將Drawable縮放到一定比例。
      <?xml version="1.0" encoding="utf-8"?>
      <scale 
          xmlns:android="http://schemas.android.com/apk/res/android"
          android:drawable="@[package:]drawable/drawable_resource"
          android:scaleGravity="[top | bottom | left | right |
              center_vertical | center_horizontal | center |
              fill_vertical | fill_horizontal | fill |
              clip_vertical | clip_horizontal]"
          android:scaleWidth="percentage"
          android:scaleHeight="percentage" />
      • android:scaleGravity :等同于BitmapDrawable的 android:gravity 。

      • android:scaleWidth 和 android:scaleHeight :指定Drawable寬/高的縮放比例,以百分比的形式表示。如 70% ,表示縮放到原來的30%。

      • 從ScaleDrawable的 draw() 源代碼來看,若等級為0時,不可見。等級默認為0,所以調用ScaleDrawable的 setLevel() 設置一個大于0的等級,它才會可見。
      public void draw(Canvas canvas) {
          final Drawable d = getDrawable();
          if (d != null && d.getLevel() != 0) {
              d.draw(canvas);
          }
      }
      • 分析ScaleDrawable的 onBoundsChange() 可看出 其內部mDrawable的大小和等級以及縮放比例的關系
      // iw常為0
      final int iw = min ? d.getIntrinsicWidth() : 0;
      // 1. MAX_LEVEL為10000,即等級的取值范圍為0~10000。
      // 2. 計算得到的最終w為其內部mDrawable最后顯示的寬度。因為是-=,所以右邊算數得到的值越大,則最終w就越小。
      // 3. level越大,其內部mDrawable就越大。
      // 4. ScaleDrawable的XML中所定義的縮放比例越大,即mState.mScaleWidth越大,則內部mDrawable就越小。
      w -= (int) ((w - iw) * (MAX_LEVEL - level) * mState.mScaleWidth / MAX_LEVEL);

      ClipDrawable

      • 對應 <clip> 標簽,用來裁剪另一個Drawable。
      <?xml version="1.0" encoding="utf-8"?>
      <clip 
          xmlns:android="http://schemas.android.com/apk/res/android"
          android:drawable="@[package:]drawable/drawable_resource"
          android:clipOrientation="[vertical | horizontal]"
          android:gravity="[top | bottom | left | right |
              center_vertical | center_horizontal | center |
              fill_vertical | fill_horizontal | fill |
              clip_vertical | clip_horizontal]" />
      • android:clipOrientation :表示裁剪方向,可選為水平和豎直。

      • android:gravity :表示對齊方式,需要和 clipOrientation 一起發揮作用。它的取值有下表各種選項,可用 | 來組合使用。

      選項 含義
      top 放在容器的頂部,不改變大小。
      若為豎直裁剪,則從底部開始裁剪。
      bottom 放在容器的底部,不改變大小。
      若為豎直裁剪,則從頂部開始裁剪。
      left 這是默認值。放在容器的左邊,不改變大小。
      若為水平裁剪,則從右邊開始裁剪。
      right 放在容器的右邊,不改變大小。
      若為水平裁剪,則從左邊開始裁剪。
      center_vertical 在容器中豎直居中,不改變大小。
      若為豎直裁剪,則從上下同時裁剪。
      center_horizontal 在容器中水平居中,不改變大小。
      若為水平裁剪,則從左右同時裁剪。
      center 居中,不改變大小。
      若為豎直裁剪,則從上下同時裁剪。
      若為水平裁剪,則從左右同時裁剪。
      fill_vertical 在豎直方向上填充容器。
      若為豎直裁剪,僅當等級為0時才能有裁剪行為。
      fill_horizontal 在水平方向上填充容器。
      若為水平裁剪,僅當等級為0時才能有裁剪行為。
      fill 完全填充容器。
      僅當等級為0時才能有裁剪行為。
      clip_vertical 附加選項,表示豎直方向的裁剪。較少使用。
      clip_horizontal 附加選項,表示水平方向的裁剪。較少使用。
      • ClipDrawable的裁剪程度由level控制,調用 setLevel() 可修改此值。其取值范圍為0~10000。0表示完全裁剪,即整個Drawable都不可見;而10000表示不裁剪。也 可將level理解為可見區域大小,0表示可見區最小,10000表示可見區最大。

      自定義Drawable

      • Drawable的工作原理很簡單,其核心就是 draw() 。系統會調用Drawable的 draw() 來繪制View的背景或ImageView的圖像,于是我們可通過重寫其 draw() 來實現自定義Drawable。

      • 通常我們沒有必要去自定義Drawable,因為無法在XML中使用自定義Drawable,這就降低了其使用范圍。

      • 創建自定義Drawable,必須重寫其 draw() 、 setAlpha() 、 setColorFilter() 、 getOpacity() 等方法。以下為自定義Drawable示例:

      /**

      • 自定義Drawable
      • Created by daking on 16/9/15. */ public class CustomDrawable extends Drawable { private Paint mPaint;

        public CustomDrawable(int color) {

         mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
         mPaint.setColor(color);
        

        }

        @Override public void draw(Canvas canvas) {

         final Rect rect =  getBounds();
         float cx = rect.exactCenterX();
         float cy = rect.exactCenterY();
         canvas.drawCircle(cx, cy, Math.min(cx, cy), mPaint);
        

        }

        @Override public void setAlpha(int alpha) {

         mPaint.setAlpha(alpha);
         invalidateSelf();
        

        }

        @Override public void setColorFilter(ColorFilter colorFilter) {

         mPaint.setColorFilter(colorFilter);
         invalidateSelf();
        

        }

        @Override public int getOpacity() {

         return PixelFormat.TRANSLUCENT;
        

        } }</code></pre>

        CustomDrawable drawable = new CustomDrawable(Color.BLUE);
        imageView.setBackgroundDrawable(drawable);
        • 若自定義的Drawable有固有大小時,要重寫 getIntrinsicWidth() 和 getIntrinsicHeight() 。因為這兩個方法會影響到View的 wrap_content 布局。

        • 注意,Drawable的內部大小不等于Drawable的實際區域大小。可通過 getBounds() 獲得Drawable的實際區域大小,一般與它的View尺寸相同。

         

        來自:http://www.jianshu.com/p/fd358b03b64c

         

 本文由用戶 q3202dasz 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!