在原生 Android 开发中,许多控件默认都是方方正正的,而我个人也比较喜欢这种设计,因为 Google 的 Material Design 就是从纸片中提炼出来的。

但是近年来 Material Design 的发展,似乎更加往大圆角的方向靠拢了。

Android 的原生控件中是不支持直接设置类似 Radius 的属性,所以又得另辟蹊径了。
Shape Attr
可以通过一个 XML 资源文件来定义,属性参考如下:
shape (形状)
最外层标签,用于定义控件的形状。
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="ring"
    android:dither="false"
    android:innerRadius="16dp"
    android:innerRadiusRatio="8"
    android:thickness="8dp"
    android:thicknessRatio="8"
    android:tint="@color/colorAccent"
    android:tintMode="add"
    android:useLevel="false">
    ...
</shape>
属性比较多,听我一一道来。
android:shape 是控件的形状,默认为矩形 rectangle,其他可选值还有椭圆 oval、线 line 和 环 ring。
android:dither 用于指定在位图的像素配置与屏幕不同时(例如:ARGB_8888 位图和 RGB_565 屏幕)是否启用位图的抖动,默认值 true,当值为 false 时则停用抖动。
android:innerRadius 是内环半径;android:innerRadius 是内环厚度比,即环的宽度比表示内环半径,默认为 3,可被 android:innerRadius 的值覆盖。android:thickness 是环的厚度,android:thicknessRatio 是环的厚度比,即环的宽度比表示环的厚度,默认为 9,可被 android:thicknessRatio 的值覆盖。这四个属性只有当形状为 ring 的时候才有效。
android:tint 用于着色,这个我们在其他控件也有用到。
android:tintMode 是着色类型,有 add、multiply、screen、src_atop、src_in 和 src_over 六个可选值,这里不细说。
android:useLevel 这个属性比较特殊,是个布尔类型,默认值为 false,一般情况下不需要修改它,为 true 时可在 LevelListDrawable 使用。
corners (圆角)
Creates rounded corners for the shape. Applies only when the shape is a rectangle.
用于定义控件的圆角属性,仅可用于矩形 Shape。
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners
        android:radius="8dp"
        android:topLeftRadius="8dp"
        android:topRightRadius="8dp"
        android:bottomLeftRadius="8dp"
        android:bottomRightRadius="8dp" />
</shape>
这个比较简单,不过多解释。
solid (填充)
A solid color to fill the shape.
用于定义控件的填充颜色。
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/colorAccent" />
</shape>
有且仅有颜色这一属性。
gradient (渐变)
Specifies a gradient color for the shape.
用于定义控件的渐变色及渐变样式等。
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:type="radial"
        android:angle="90"
        android:startColor="@color/colorPrimaryDark"
        android:centerColor="@color/colorAccent"
        android:endColor="@color/colorPrimary"
        android:centerX="50%"
        android:centerY="50%"
        android:gradientRadius="8dp"
        android:useLevel="false" />
</shape>
这个相对比较复杂,分组来说。
android:type 是渐变的样式,有三个可选值,线性渐变 linear 是默认值,另外还有放射渐变 radial 和扫描渐变 sweep。
android:angle 是渐变角度,须为 45 的整倍数,其中 0 为从左到右,90 为从上到下。
android:startColor、android:centerColor 和 android:endColor 分别是渐变的起始点、中间点和结束点颜色,但你可以按需设置,因为其支持两色渐变和三色渐变,即当选择两色渐变时,android:centerColor 可以不用填写。
android:centerX 和 android:centerY 是渐变中心点 X 和 Y 的相对位置,取值范围为 0~1。
android:gradientRadius 是渐变的半径,只有当渐变类型为 radial 时才有效。
android:useLevel 这个属性比较特殊,是个布尔类型,默认值为 false,一般情况下不需要修改它,而使用 LevelListDrawable 时就要设置其为 true。
stroke (描边)
A stroke line for the shape.
用于定义控件的描边属性。
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <stroke
        android:width="8dp"
        android:color="@color/colorAccent"
        android:dashWidth="8dp"
        android:dashGap="8dp" />
</shape>
android:width 是描边的宽度。android:color 是描边的颜色。
一般情况下描边为实线,如果想设置虚线,则需要另外两个属性,android:dashWidth 是指虚线段的长度,android:dashGap 是指虚线段间隔的长度。
padding (边距)
Padding to apply to the containing View element (this pads the position of the View content, not the shape).
用于定义控件的边距属性。
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <padding
        android:bottom="4dp"
        android:left="4dp"
        android:right="4dp"
        android:top="4dp" />
</shape>
这个也比较简单,不过多解释。
size (大小)
The size of the shape.
用于定义控件的尺寸属性。
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <size
        android:width="128dp"
        android:height="128dp" />
</shape>
同样比较简单,不过多解释。
Usage
用法也不复杂,在「drawable」文件夹中新建一个 XML 资源文件,将上面的属性按照需要进行组合即可。
比如,我建一个「button_shape.xml」,用来定义 Button 控件的形状。
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="@color/colorAccent" />
    <corners
        android:topLeftRadius="5dp"
        android:topRightRadius="10dp"
        android:bottomLeftRadius="15dp"
        android:bottomRightRadius="0dp" />
</shape>
代码并不难理解,形状为矩形,颜色设定为主题色,为四个圆角半径设定为 不同的值。
然后使用其在控件属性中设置为 android:background:
<Button
    android:layout_width="128dp"
    android:layout_height="wrap_content"
    android:background="@drawable/button_shape"
    android:text="Button" />
效果如下:

其实 Shape 的可配置属性并没有很复杂,所以学起来也不会很难上手,但是却足够我们使用。
