Android Drawable系列
日常开发中,一些简单的背景或者图形都会使用xml的shape
标签完成,经常使用在按钮的背景上。
shape
的优点还是很多的
- 文件比切图小
- 节约内存
- 支持拉伸
shape
的属性虽然比较简单,但是也能绘制出一些比较复杂的形状
概览
首先来看看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"]//分别为矩形、椭圆、线、环。默认为矩形rectangle
android:innerRadius="integer" // shape为ring时有效,内环半径
android:innerRadiusRatio="float" // shape为ring时有效,内环的厚度比,即环的图形宽度与内环半径的比例,按照这个比例计算内环半径,默认为3,可被innerRadius值覆盖
android:thickness="integer" // shape为ring时有效,环的厚度
android:thicknessRatio="float" // shape为ring时有效,环的厚度比,即环的图形宽度与环的厚度的比例,按照这个比例计算环的厚度,默认为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的整数倍数
android:centerColor="integer" // 渐变中间位置颜色
android:startColor="color" // 渐变开始位置颜色
android:endColor="color" // 渐变结束位置颜色
android:centerX="float" // 设置渐变中心的X坐标,取值区间[0,1],默认为0.5,即中心位置
android:centerY="float" // 设置渐变中心的Y坐标,取值区间[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
经常使用的就是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
就是整个区域的填充色
corners
则是控制了背景的4个角的圆角半径
stroke
控制了描边的属性,color
表示线的颜色;width
描边的宽度,其实就是图中红线的高度;dashWidth
表示虚线中红线的宽度;dashGap
表示虚线间隔宽度,也就是红色之间的间隔距离
corners属性覆盖
再来看看corners
标签的属性覆盖规则。下图中将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
的显示就会根据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的整数倍。
android:centerX和android:centerY
这两个属性是控制渐变中心位置的坐标的,取值区间[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>
经过查资料和一些测试,使用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
在使用其他的属性方面规则基本一直,只是corners
标签不在具有任何效果。
最后是ring
,关于ring的属性比其他的三种图形要多出4个属性
- innerRadius,shape为ring时有效,内环半径
- innerRadiusRatio,shape为ring时有效,内环的厚度比,即环的图形宽度与内环半径的比例,按照这个比例计算内环半径,默认为3,可被innerRadius值覆盖
- thickness,shape为ring时有效,环的厚度
- thicknessRatio,shape为ring时有效,环的厚度比,即环的图形宽度与环的厚度的比例,按照这个比例计算环的厚度,默认为9,可被thickness值覆盖
上图中第一个环的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
,这基本就是默认的一个环了,内环半径和环的厚度都是分别是按3和9的比例计算的,后面会具体讲解这两个值得意思。
第二个环,则是添加android:thickness="5dp"
属性,设置了环的厚度为5dp
第三个环,则是添加android:innerRadius="10dp"
属性,设置内环半径为10dp
第四个环,可以算解释了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
两个标签不起作用,其他的标签可以正常的使用