【Android Drawable系列】- shape xml属性详解

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

经常使用的就是solidcornersstroke这三个标签

下面是这个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:widthandroid:height

但是,在作为背景的情况下,shape的size属性并不是完全有效的,最后的显示效果还是会由view来决定,size只是在view的宽(或高)为wrap_content且显示内容后的实际大小不超过size所设置的值得时候才会生效。这个效果其实比较类似minWidth
minHeight两个属性的效果。

下图中,左边的内容没有超出,按照size所设置的大小显示,而右边的内容超出了size所设置的大小,按照实际大小显示。这里比较简单,不上代码了。

不要这样就觉得size没有什么作用,例如下图

截图的原因,图片被放大了,这些圆使用ImageViewsrc显示时,ImageView只需要设置wrap_content就可以按照设置的大小显示了。

当然,如果你修改了ImageView的大小,那shape的显示就会根据ImageViewscaleType来决定最后的显示效果了。

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个按钮的shapeandroid:angle属性值分别是90、180、270。注意,android:angle属性需要时45的整数倍。

android:centerX和android:centerY

这两个属性是控制渐变中心位置的坐标的,取值区间[0,1],默认为0.5

上图中,三种渐变类型都设置了中心点的位置,radialsweep两种类型比较好理解,就是控制中心在图形中的的相对位置。

linear类型也会受到这两个属性的改变,因为是线性所以作用应该是对线的中心点的控制,我试了一下,centerX或者centerY都能控制渐变的中心点,而且不受android:angle属性影响。但是centerXcenterY同时使用时,不存在属性前后顺序而导致属性覆盖的的情况,只有centerX起作用。

android:gradientRadius

设置渐变的半径,当type为放射性渐变radial时有效,差异效果如下图:

solidgradient同时使用时,在代码中比较靠下的标签会覆盖之前的标签属性

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标签,sizeheight也必须比大于虚线高度
  • 4.0 以上手机,默认使用硬解码,虚线在真机会显示成实线,可以关闭页面的硬件加速,也可以给相关的view设置成软解layerType="software"

再来是oval,虽然表示的是椭圆,其实只需要显示图形的view是正方形就可以显示成圆了。之前在使用size就是以圆为例子举例的,在ImageViewsrc中使用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的宽高,来保证显示圆。

ovalrectangle在使用其他的属性方面规则基本一直,只是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>

可以看到并没有设置什么其他的属性,只是设置了solidsize,这基本就是默认的一个环了,内环半径和环的厚度都是分别是按3和9的比例计算的,后面会具体讲解这两个值得意思。

第二个环,则是添加android:thickness="5dp"属性,设置了环的厚度为5dp

第三个环,则是添加android:innerRadius="10dp"属性,设置内环半径为10dp

第四个环,可以算解释了innerRadiusRatiothicknessRatio两个属性,具体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>

innerRadiusRatiothicknessRatio两个属性都是对比view最终显示的大小来计算的,可以对应着两个公式:
innerRadius = view.width / innerRadiusRatio
thickness = view.width / thicknessRatio

这样以来着两个属性就比较好理解了

对于ring的使用还有几点需要注意:

  • 必须写useLevel="false",否则不显示
  • 如果android:thicknessandroid:innerRadius设置了值,无论view的大小如何设置,将不会影响图片大小,这有可能会导致图形显示不全。
  • paddingcorners两个标签不起作用,其他的标签可以正常的使用
PS:好了,shape的基本属性算是了解完了,如有不正确的地方,还请大佬指正。

如果喜欢该文章,可以扫码领个红包支持一下

图片发自简书App
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • 伊稚斜华美,於单傲娇,总以为狼群里长大的小玉终究属于草原,却不想她一生爱恨纠葛都在精致的长安。 月牙泉边,她初次遇...
    卷卷卷了个卷卷阅读 1,150评论 0 2
  • “两线同交叉模式”:指在同一天时间里,平滑移动平均线(EX-PMA)指标的短周期(快线)于长周期(慢线)形成金叉且...
    f4f769f861f0阅读 521评论 0 3
  • 一点墨色一夜长 缭绕过空旷星光 一笔何以书古江 镌得茫茫刺骨凉 夜深灯难休 影曳人彷徨 偶觉花落归木桩 忽而梦舟过...
    阿甯Linn阅读 179评论 1 8