
日常開發(fā)中,一些簡單的背景或者圖形都會使用xml的shape標簽完成,經(jīng)常使用在按鈕的背景上。
shape的優(yōu)點還是很多的
- 文件比切圖小
- 節(jié)約內存
- 支持拉伸
shape的屬性雖然比較簡單,但是也能繪制出一些比較復雜的形狀
概覽
首先來看看shape標簽所支持的標簽以及屬性,如下圖:

左側是shape標簽的自身屬性,右側是shape標簽所支持的標簽和標簽的屬性。
下面是一份xml屬性實例和說明
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:dither=["true" | "false"] //將在位圖的像素配置與屏幕不同時(例如:ARGB 8888 位圖和 RGB 565 屏幕)啟用位圖的抖動;值為“false”時則停用抖動。默認值為 true。
android:shape=["rectangle" | "oval" | "line" | "ring"]//分別為矩形、橢圓、線、環(huán)。默認為矩形rectangle
android:innerRadius="integer" // shape為ring時有效,內環(huán)半徑
android:innerRadiusRatio="float" // shape為ring時有效,內環(huán)的厚度比,即環(huán)的圖形寬度與內環(huán)半徑的比例,按照這個比例計算內環(huán)半徑,默認為3,可被innerRadius值覆蓋
android:thickness="integer" // shape為ring時有效,環(huán)的厚度
android:thicknessRatio="float" // shape為ring時有效,環(huán)的厚度比,即環(huán)的圖形寬度與環(huán)的厚度的比例,按照這個比例計算環(huán)的厚度,默認為9,可被thickness值覆蓋
android:tint="color" // 給shape著色
android:tintMode=["src_in" | "src_atop" | "src_over" | "add" | "multiply" | "screen"] // 著色類型
android:useLevel=["true" | "false"] // 較少用,一般設為false,否則圖形不顯示。為true時可在LevelListDrawable使用
android:visible=["true" | "false"] >
<!-- 圓角 -->
<corners
android:radius="integer" // 圓角半徑,設置下面四個屬性時,對應的位置屬性會被覆蓋
android:topLeftRadius="integer" // 左上角圓角半徑
android:topRightRadius="integer" // 右上角圓角半徑
android:bottomLeftRadius="integer" // 左下角圓角半徑
android:bottomRightRadius="integer" // 右下角圓角半徑
/>
<!-- 漸變 -->
<gradient
android:type=["linear" | "radial" | "sweep"]// 漸變類型,線性、放射性、掃描性;默認為線性
android:angle="integer" // 漸變角度,漸變類型為linear時有效;默認為0,從左至右漸變,角度逆時針方向計算,角度需要時45的整數(shù)倍數(shù)
android:centerColor="integer" // 漸變中間位置顏色
android:startColor="color" // 漸變開始位置顏色
android:endColor="color" // 漸變結束位置顏色
android:centerX="float" // 設置漸變中心的X坐標,取值區(qū)間[0,1],默認為0.5,即中心位置
android:centerY="float" // 設置漸變中心的Y坐標,取值區(qū)間[0,1],默認為0.5,即中心位置
android:gradientRadius="integer" // type為放射性漸變radial時有效,漸變的半徑
android:useLevel=["true" | "false"] // 與shape中該屬性的一致
/>
<!-- 內邊距 -->
<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" // 虛線間隔
/>
</shape>
因為shape中的屬性更的是組合使用,所以舉例沒法單獨只使用一個標簽。
solid、corners和stroke
經(jīng)常使用的就是solid、corners、stroke這三個標簽

下面是這個Button背景的xml代碼
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="10dp"/>
<solid android:color="#008577"/>
<stroke
android:width="3dp"
android:color="#D81B60"
android:dashWidth="10dp"
android:dashGap="5dp"/>
</shape>
solid就是整個區(qū)域的填充色
corners則是控制了背景的4個角的圓角半徑
stroke控制了描邊的屬性,color表示線的顏色;width描邊的寬度,其實就是圖中紅線的高度;dashWidth表示虛線中紅線的寬度;dashGap表示虛線間隔寬度,也就是紅色之間的間隔距離
corners屬性覆蓋
再來看看corners標簽的屬性覆蓋規(guī)則。下圖中將radius屬性設置為10dp,并同時設置給其他的四個屬性不同的值,從圖中可以看出四個屬性將都radius屬性覆蓋了。

具體的xml代碼:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:bottomLeftRadius="30dp"
android:bottomRightRadius="40dp"
android:radius="10dp"
android:topLeftRadius="0dp"
android:topRightRadius="20dp"/>
<solid android:color="#008577"/>
</shape>
padding
再來看看padding標簽的作用,圖片如下:

第一行的TextView的背景沒有設置padding屬性;第二行則是使用了padding標簽,不低的地方在于有無內容的差別。shape的xml代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#008577"/>
<padding
android:bottom="10dp"
android:left="10dp"
android:right="10dp"
android:top="10dp"/>
</shape>
shape中雖然使用了padding標簽,但是在被設置該背景的view上依然可以通過修改paddingLeft等對應的相關屬性進行覆蓋。
size
size控制圖形的寬高尺寸,對應屬性也就android:width和android:height
但是,在作為背景的情況下,shape的size屬性并不是完全有效的,最后的顯示效果還是會由view來決定,size只是在view的寬(或高)為wrap_content且顯示內容后的實際大小不超過size所設置的值得時候才會生效。這個效果其實比較類似minWidth
和minHeight兩個屬性的效果。
下圖中,左邊的內容沒有超出,按照size所設置的大小顯示,而右邊的內容超出了size所設置的大小,按照實際大小顯示。這里比較簡單,不上代碼了。

不要這樣就覺得size沒有什么作用,例如下圖

截圖的原因,圖片被放大了,這些圓使用ImageView的src顯示時,ImageView只需要設置wrap_content就可以按照設置的大小顯示了。
當然,如果你修改了ImageView的大小,那shape的顯示就會根據(jù)ImageView的scaleType來決定最后的顯示效果了。
gradient
不太清楚gradient標簽的使用頻率,畢竟是UI效果,實際工作中涉及到漸變的時候基本都是設計小姐姐直接給圖的。不過不妨礙我們了解gradient的用法。
android:type
這里先說android:type屬性,表示漸變類型,有三個可以選擇的屬性linear線性、radial放射性、sweep掃描性,默認為線性
下圖,從左到右的中android:type分別是linear線性、radial放射性、sweep掃描性

- 線性:比較好理解,就是一條線從左到右,準確的說是從一邊到另一邊漸變,而這個方向是可以調整的,后面會說明
- 放射性:從一個中心點向外漸變
- 掃描性:這個比較像雷達,具體看圖,我描述不出來,不過也是有中心點的
漸變顏色
先以默認漸變類型來看下主要的三個屬性:
- android:centerColor 漸變中間位置的顏色
- android:endColor 漸變結束位置的顏色
- android:startColor 漸變開始位置的顏色

上圖中第一個按鈕,設置了開始顏色是紅的,中間顏色是白色,結束顏色是綠的,具體代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:centerColor="#FFFFFF"
android:startColor="#D81B60"
android:endColor="#008577"/>
<corners android:radius="10dp"/>
</shape>
android:angle
start -> end默認的方向是從左到右,通過設置android:angle屬性可以修改這個方向,0 -> 360 增加時,方向是逆時針調整的。上圖中,第2、3、4個按鈕的shape的android:angle屬性值分別是90、180、270。注意,android:angle屬性需要時45的整數(shù)倍。
android:centerX和android:centerY
這兩個屬性是控制漸變中心位置的坐標的,取值區(qū)間[0,1],默認為0.5

上圖中,三種漸變類型都設置了中心點的位置,radial和sweep兩種類型比較好理解,就是控制中心在圖形中的的相對位置。
linear類型也會受到這兩個屬性的改變,因為是線性所以作用應該是對線的中心點的控制,我試了一下,centerX或者centerY都能控制漸變的中心點,而且不受android:angle屬性影響。但是centerX和centerY同時使用時,不存在屬性前后順序而導致屬性覆蓋的的情況,只有centerX起作用。
android:gradientRadius
設置漸變的半徑,當type為放射性漸變radial時有效,差異效果如下圖:

當
solid和gradient同時使用時,在代碼中比較靠下的標簽會覆蓋之前的標簽屬性
shape
shape的標簽屬性都了解完了,接著就是shape自身的屬性了
前面舉例的都是矩形,也就是android:shape="rectangle"的情況下,接下來看看其他三種類型,
首先是line,因為虛線和實線相差兩個屬性,就直接用虛線舉例了

下面是具體的xml代碼:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line">
<stroke
android:width="3dp"
android:color="#D81B60"
android:dashWidth="10dp"
android:dashGap="5dp"/>
<size android:height="10dp"/>
</shape>
經(jīng)過查資料和一些測試,使用line類型有些限制
- 必須使用
stroke標簽,view顯示的高度必須大于(必須是大于,等于都不行)stroke標簽中width寬度屬性的值。也就是說,view所設置的高度需要大于虛線高度;如果使用了size標簽,size的height也必須比大于虛線高度 - 4.0 以上手機,默認使用硬解碼,虛線在真機會顯示成實線,可以關閉頁面的硬件加速,也可以給相關的
view設置成軟解layerType="software"
再來是oval,雖然表示的是橢圓,其實只需要顯示圖形的view是正方形就可以顯示成圓了。之前在使用size就是以圓為例子舉例的,在ImageView的src中使用shape,xml代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#008577"/>
<size android:width="20dp"
android:height="20dp"/>
</shape>
當然,也可以通過限制view的寬高,來保證顯示圓。
oval和rectangle在使用其他的屬性方面規(guī)則基本一直,只是corners標簽不在具有任何效果。
最后是ring,關于ring的屬性比其他的三種圖形要多出4個屬性
- innerRadius,shape為ring時有效,內環(huán)半徑
- innerRadiusRatio,shape為ring時有效,內環(huán)的厚度比,即環(huán)的圖形寬度與內環(huán)半徑的比例,按照這個比例計算內環(huán)半徑,默認為3,可被innerRadius值覆蓋
- thickness,shape為ring時有效,環(huán)的厚度
- thicknessRatio,shape為ring時有效,環(huán)的厚度比,即環(huán)的圖形寬度與環(huán)的厚度的比例,按照這個比例計算環(huán)的厚度,默認為9,可被thickness值覆蓋

上圖中第一個環(huán)的xml代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:useLevel="false"
android:shape="ring">
<solid android:color="#008577"/>
<size android:width="100dp"
android:height="100dp"/>
</shape>
可以看到并沒有設置什么其他的屬性,只是設置了solid和size,這基本就是默認的一個環(huán)了,內環(huán)半徑和環(huán)的厚度都是分別是按3和9的比例計算的,后面會具體講解這兩個值得意思。
第二個環(huán),則是添加android:thickness="5dp"屬性,設置了環(huán)的厚度為5dp
第三個環(huán),則是添加android:innerRadius="10dp"屬性,設置內環(huán)半徑為10dp
第四個環(huán),可以算解釋了innerRadiusRatio和thicknessRatio兩個屬性,具體xml代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:useLevel="false"
android:innerRadiusRatio="3"
android:thicknessRatio="100"
android:shape="ring">
<solid android:color="#008577"/>
<size android:width="200dp" android:height="200dp"/>
</shape>
innerRadiusRatio和thicknessRatio兩個屬性都是對比view最終顯示的大小來計算的,可以對應著兩個公式:
innerRadius = view.width / innerRadiusRatio
thickness = view.width / thicknessRatio
這樣以來著兩個屬性就比較好理解了
對于ring的使用還有幾點需要注意:
- 必須寫
useLevel="false",否則不顯示 - 如果
android:thickness和android:innerRadius設置了值,無論view的大小如何設置,將不會影響圖片大小,這有可能會導致圖形顯示不全。 -
padding和corners兩個標簽不起作用,其他的標簽可以正常的使用
PS:好了,shape的基本屬性算是了解完了,如有不正確的地方,還請大佬指正。
如果喜歡該文章,可以掃碼領個紅包支持一下
