這些 Drawable 的小技巧,你都了解嗎?

173

一、前言

在 Android 的開發(fā)過程中,Drawable 經常會被用到,一般會用 Drawable 為 View 設置一個顯示的效果。而在 Android 下,也提供了很多 Drawable 的默認實現,它們涉及到的內容非常的多,從屬性到方法,但是日常生活中,會用到的只有那么些方式。

本文就在工作中,Drawable 的常用方式,整理出一篇文章,會攜帶一些場景,如有缺漏的,可以在文末留言,本文采用精益編寫,如有必要,會一直長期更新。

二、什么是 Drawabe

Drawable 實際上是一個抽象類,主要用于將一個可繪制的資源,按要求繪制成圖形,顯示在屏幕之上。

Android 為了讓開發(fā)者更方便的使用 Drawable ,提供了很多 Drawable 的實現類,并提供對應的 xml 的屬性配置。

例如:

/d-shapedefault.png

同時它也可以使用代碼的方式實現,它們的效果是一樣的。

/d-shapecode.png

實際上,不管是使用 xml 資源的方式,還是直接在邏輯中硬編碼的方式,它們最終顯示的效果都是一樣的,如下圖,一個藍色的方塊:

/d-shapeimage.png

Android 中,為我們提供了非常多默認的 Drawable,正常來說,一般是足夠我們使用的,它們的關系如下圖:

/d-normal.png

基本上,從 XxxDrawable 這種類名,就可以看出來它對應的 Xml 資源的命名,唯一需要注意的是 <shape/> 的實現類是 GradientDrawable ,而不是 ShapeDrawable。

三、Drawable 的常用實現

3.1 圓角的按鈕

有些 App 中,按鈕的圓角,如果背景只是一個純色或者是簡單的規(guī)則漸變,是可以使用 <shape/> 來完成的,如前面示例一樣。

如果想要為其增加一個圓角,可以在 <shape/> 中使用 corners 屬性,它支持設置一個 android:radius ,用來設置四個角落的圓角角度,當然也提供了單獨的屬性去設置某個角的圓角角度,例如,android:topLeftRadius 就是設置左上的圓角的。

/d-shapecornes.png

實現的效果如下:

/d-shapecornesimg.png

3.2 帶邊框的圓角按鈕

想在圓角的 <shape/> 上,加一個邊框,可以使用 stroke 屬性,當然,不是設置 corners 屬性,它就不是一個圓角的效果了。

stroke 用于設置邊框,可以指定顏色和邊框的寬度。

/d-strokexml.png

可以看到這里指定了一個黃色的邊框,效果如下圖:

/d-strokeimage.png

3.3 單邊邊框

在 <shape/> 中,如果使用 stroke 來設置邊框,它會在四周都加上邊框,但是有時候,我們只需要在底部或者單邊繪制一個邊框的效果,例如:一個列表頁里每一項的分割線。

這個時候,就可以使用 <layout-list/>,使用兩個 shape 來疊加實現。

bottom-line

這樣的一個 Drawable,如果作為背景的話,顯示效果就是在白色背景下,有一條 1px 的灰線。當然其他方向可以參考這個方案,截圖發(fā)現 1px 的線不太明顯,這里就不放圖了。

3.4 漸變的背景色

<shape/> 除了支持一個純色規(guī)則圖案,它還可以實現漸變的效果,用的最多的,就是線性漸變。

例如一些視頻 App 的 UI 設計,會將視頻名稱直接布局在視頻海報上,就可以使用線性漸變的 <shape/> 來實現簡單的背景效果,使其在白色的視頻海報上,顯示的效果依然能看得清楚文字。

例如一般的視頻App :

/d-tengxun.png

看到其實海報下面的文字,底部是有一個漸變的背景色的。

這種漸變的效果,可以使用 gradient 標簽來設置。

/d-gradientxml.png

gradient 支持的屬性,基本上看名稱就可以知道意思,唯一需要注意的是 android:angle 這個屬性,用于設定漸變的角度,但是它不是任何值都支持的,只支持 45 的倍數。

效果如下圖:

/d-gradientimage.png

3.5 海報的默認圖

通常在圖片加載的過程中,會為其定義一個默認圖片。一般的設計都是會將這個默認圖做的非常的簡潔,例如中間一個 App 主題的 Icon,然后其它地方純色鋪平。

類似下面這種效果:

/d-aqiyi.png

這種默認的圖片,當然你可以使用一張等大的圖,但是這樣不利于適配,不同的 UI 設計尺寸,你需要提供不同的圖片。當然你也可以使用 9patch 的圖片,但是你會發(fā)現有些 density 為 2.75 這種奇葩的手機下,圖標會微微偏移,不在正中間。所以這里可以使用一個<layer-list/> 的 Drawable 來實現。

<layer-list/> 是一個帶層級效果的 Drawable ,有點類似于布局中的 FrameLayout 的效果。它支持設置多個 Drawable ,并將它們疊加在一起。

所以這樣的場景下,我們就需要一個純色的背景加一張小圖,即可實現默認圖的效果。

下面是 xml 的實現代碼:

/d-layerxml.png

下面是運行后的效果圖:

/d-layerimage.png

3.6 帶按下效果的按鈕

對一個按鈕,設計一個按下的效果。可以使用 <selector/> 這個 Drawable。它支持在不同的狀態(tài)下,顯示不同的 Drawable。

<selector> 同樣也支持設置多個 Drawable ,區(qū)別在于你需要額外的為每個 Drawable 設置不同的狀態(tài),如果不設置,則為默認顯示的狀態(tài)。

這些不同的狀態(tài),在 xml 里,都是以 android:state_Xxx 開頭來定義的,將其設置為 true 即可生效。

Android 為我們提供了非常多的狀態(tài),比較常用的有:

  • state_pressed:按下的效果。
  • state_checkable:是否可設置 checked 狀態(tài)的效果。
  • state_selected:支持 selected 并且當前處于 selected 的效果。
  • state_checked:支持 checkeable 并且當前處于 checked 的效果。

接下來讓我們看一個實際的按鈕例子,這里只為其設置按下的效果,xml 代碼如下:

/d-pressxml.png

實現效果如下:

/d-pressDemo.gif

3.7 一個帶按下效果的圓角按鈕

這個沒啥好說的,結合上面的效果就可以做到。你可以選擇將它們寫在不同的 Drawable 中,也可以在一個 xml 文件中,使用不同 item 來完成。Item 標簽是可以支持內部再嵌套一個 Drawable 的。

/d-cornespress.png

3.8 帶按下動畫

按下效果除了使用 <selector> 做一個變色的效果之外,在 Api Level 21 之后,可以嘗試使用 StateListAnimator 來實現一個 Material Design 的按下效果。

具體細節(jié)可以看看我之前的一篇文章:《利用 StateListAnimator 為你的點擊加個動畫吧!

StateListAnimtor 使用起來非常的簡單:

  1. 在 res 中創(chuàng)建一個 animator 目錄。
  2. 在其中創(chuàng)建一個 xml 資源文件,就是一個 <selector/> 。
  3. 在 xml 資源中使用 <selector/> 中,定義我們 View 切換狀態(tài)時候的動畫,其實就是一個個 <objectAnimator/>。
  4. 最終將定義好的 animtor 通過 View 的 setStateListAnimator() 方法或者 android:stateListAnimator 屬性,設置到 View 上。

舉個例子。

首先在 /res/animtor 目錄下,創(chuàng)建一個 btn_press_animator.xml 文件。

animator-xml

可以看到,和 StateListDrawable 一樣,它也是通過 android:state_xxx 屬性來定義不同的 Animator 的,如果存在多個 Animator ,可以使用 <set/> 標簽將其包裹起來。 這里只是簡單的在 state_pressed 的時候,做了一個縮小的動畫。

然后,定義一個 View,為其設置屬性 android:stateListAnimator="@animator/btn_press_animator"

來看看運行的效果:

[圖片上傳失敗...(image-e0ebc3-1512715336178)]

3.9 三角形的 Drawable

?假如有類似氣泡提示的效果,如下圖。

qipao

這樣的效果,除了使用 9patch 來實現之外,還可以拿兩個 Drawable 來拼接實現,這就需要一個圓角的矩形和一個三角的 Drawable。

三角 Drawable 的實現思路很清奇,是使用一個矩形的 shape ,通過使用 rotate 實現的旋轉,來達到尖角的效果。

daosanjiao

這個例子,就是上圖的實現效果,是一個黃色的倒三角。如果想要的是一個正三角,只需要改變旋轉的角度就可以了。

zhensanjiao

3.10 Tint 著色的 Drawable

在 Drawable 中,如果使用的是 BitmapDrawable 或者 NinePatchDrawable(9patch) 的資源的話,可以使用 android:tint 屬性為其著色。

默認情況下,待著色的圖片資源,會將其所有有顏色地方,都著色成我們指定的顏色,但是會保留透明度。

/d-tintxml.png

效果圖如下,上面是原圖,下面是使用 tint 之后的效果:

/d-tintimage.png

前面這里給的是 tint 默認的效果,還可以通過 android:tintMode 指定成不同的著色效果,例如下面將 android:tintMode 指定成 screen 之后,效果就完全不一樣了。

/d-tintimage1.png

3.11 鋪平的 Drawable

有時候,作為一些有規(guī)則的圖片的背景,可以使用一張很小的圖片,然后設定 android:tileMode 屬性,為其設定一個平鋪的效果。

[圖片上傳失敗...(image-916a9a-1512715336178)]

tileMode 可以指定多個屬性值,用于指定不同的效果,以下就是兩個比較常用的,上圖使用的是 repeat ,下圖使用的是 mirror。

/d-tileimage.png

3.12 狀態(tài)可控的層級 Drawable

如果想要一個 ImageView 上,根據不同的條件顯示不同的 Drawable ,可以使用 <level-list/> 。從名字上就可以看出它是一個帶層級的 Drawable 組合,和 <selector/> 很像,但是區(qū)別在于它的顯示狀態(tài)是我們邏輯可控的。最常見的例子是拿它實現一個開關的燈泡,兩態(tài)的圖片,一個表示開燈,一個表示關燈,相信大家應該都見過例子。

今天舉一個例子,給某個圖標加紅點的邏輯。當然我們也可以使用通過一個 FrameLayout 來實現,但是今天我們試試用 <level-list/> 來實現它。

red-point

這里使用一個 <level-list/> ,內部根據不同的 maxLevel 和 minLevel 來控制范圍,這里只有兩態(tài),所以直接讓它們取值一致。紅點使用 <layer-list> 做了一個層疊,在右上角上,直接畫了一個大小為 5dp 的紅色圓點。

最終我們可以通過 ImageView 的 setImageLevel() 方法來控制顯示的內容。

d-red-demo

四、結語

到這里基本上涵蓋了 Drawable 大部分的使用場景,在實際例子中學東西是印象最深刻的。當然,Drawable 的使用不止這些,還有一些例如拿 ClipDrawable 來實現一個切割進度的效果之類的,這種還需要寫邏輯代碼,就不在本文的范圍內了,本文主要介紹一些靜態(tài)能實現的效果。

你只需要掌握最基本的規(guī)則,什么 Drawable 能實現什么效果,具體碰到實際需求的時候,再來細致的研究,基本上微調一下就可以使用。

如果你還又什么更有意思的 Drawable 使用技巧,歡迎在文末留言,我們一起討論一下,如有需要,會持續(xù)更新。

今天在承香墨影公眾號的后臺,回復『成長』。我會送你一些我整理的學習資料,包含:Android反編譯、算法、設計模式、虛擬機、Linux、Kotlin、Python、爬蟲、Web項目源碼。

推薦閱讀:

[圖片上傳失敗...(image-b12cfc-1512715336178)]

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容