Android 开发艺术探索笔记之六 -- Android 的
整理一下,基本只作为 知识清单 使用
学习内容:
- Drawable 的层次关系
- Drawable 分类
- 自定义 Drawable 的相关知识
Drawable 简介
Drawable 表示的是一种可以在 canvas 上进行绘制的图像的 抽象概念。实际开发中,Drawable 常被用来作为 View 的背景使用。
优点:
- 使用简单,比自定义 View 的成本低
- 非图片类型的 Drawable 占用空间较小,有利于减小 apk 的大小。
层次关系:
- Drawable 是一个抽象类,是所有 Drawable 对象的基类。
- 每个具体的 Drawable 都是它的子类,比如 ShapeDrawable,BitmapDrawable 等。
Drawable 内部宽 / 高
- 通过 getIntrinsicWidth 和 getIntrinsicHeight 两个方法获取。
- 并非所有 Drawable 都有内部宽/高(图片形成的 Drawable 内部宽/高等同于图片的宽/高,颜色形成的 Drawable 没有内部宽/高的概念)
- Drawable 的内部宽/高不等同于它的大小,一般来说,Drawable 没有大小概念,当作为 View 背景时,会被拉甚至 View 的同等大小。
Drawable 分类
1.BitmapDrawable
表示的就是一张图片,可以直接引用原始的图片,也可以通过 xml 方式描述它。
<?xml version="1.0" encoding="utf-8"?>
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@[package:]drawable/drawable_resource"
android:antialias=["true"|"false"]
android:dither=["true"|"false"]
android:filter=["true"|"false"]
android:gravity=["top"|"bottom"|"left"|"right"|"center_vertical"|"fill_vertical"|"center_horizontal"|"fill_horizontal"|"center"|"fill"|"clip_vertical"|"clip_horizontal"]
android:mipMap=["true"|"false"]
android:tileMode=["disabled"|"clamp"|"repeat"|"mirror"]></bitmap>
属性说明:
- android:src:图片的资源 ID
- android:antialias:抗锯齿,牺牲清晰度使图片平滑。建议开启
- android:dither:抖动效果,当图片像素配置和手机屏幕的像素配置不一致时,开启此选项可以让高质量图片在低质量屏幕上还能保持较好的小时效果。建议开启
- android:filter:过滤效果,图片拉伸或压缩时,开启此选项可以保持较好的显示效果。建立开启
- android:gravity:当图片小于容器的尺寸时,设置此选项对图片进行定位,多个属性值可以通过 "|" 来组合使用
- android:mipMap:纹理映射,默认值为 false,日常开发中不涉及此项
- android:tileMode:平铺模式,默认为 disabled,关闭平铺模式;clamp 表示图片四周的像素扩散到周围区域;repeat 表示简单的水平和垂直方向上的平铺效果;mirror 表示一种水平和竖直方向上的镜面投影效果;另外需要注意,当开启平铺模式后, gravity 属性将被忽略。
2.ShapeDrawable
可以理解为通过颜色来构造的图形,既可以是纯色的图形,也可以是具有渐变效果的图形。
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape=["rectangle"|"oval"|"line"|"ring"]>
<corners
android:bottomLeftRadius="integer"
android:bottomRightRadius="integer"
android:radius="integer"
android:topLeftRadius="integer"
android:topRightRadius="integer" />
<gradient
android:angle="integer"
android:centerColor="integer"
android:centerX="integer"
android:centerY="integer"
android:endColor="color"
android:gradientRadius="integer"
android:startColor="color"
android:type=["linear"|"radial"|"sweep"]
android:useLevel=["false"|"false"] />
<padding
android:left="integer"
android:right="integer"
android:top="integer"
android:bottom="integer"/>
<size
andorid:width="integer"
andorid:height="integer"/>
<solid android:color="color" />
<stroke
android:width="integer"
android:color="color"
android:dashGap="integer"
android:dashWidth="integer" />
</shape>
属性说明:
-
android:shape:表示图形的形状,有四种:rectangle矩形,oval椭圆,line横线,ring圆环。
- 默认为矩形
- line 和 ring 必须通过 <stroke> 指定线的宽度和颜色等信息
- ring 有特殊的5个属性:
- android:innerRadius:圆环内半径,优先级大于android:innerRadiusRatio
- android:thickness:圆环的厚度,优先级大于 android:thicknessRatio
- android:innerRadiusRatio:内半径占整个 Drawable 宽度的比例
- android:thicknessRatio:厚度占整个 Drawable 宽度的比例
- android:useLevel:一般都使用 false,除非当作 LevelListDrawable 来使用。
-
<corners>:表示 shape 的四个角的圆角角度,单位是 px,只适用于 矩形 shape。有如下 5 个属性:
- android:radius:为四个角同时设定相同角度,优先级低。
- andorid:topLeftRadius:左上角的角度
- andorid:topRightRadius:右上角的角度
- andorid:bottomLeftRadius:左下角的角度
- andorid:bottomRightRadius:右下角的角度
-
<gradient>:与 <solid> 互斥,solid 表示纯色填充,gradient 表示渐变效果,有以下属性:
- android:angle:渐变的角度,默认为0,其值必须是 45 的倍数,0表示从左往右,90 表示 从上到下。
- android:centerX:渐变的中心横坐标
- android:centerY:渐变的中心纵坐标
- android:startColor:渐变起始色
- android:centerColor:渐变的中间色
- android:endColor:渐变的结束色
- android:gradientRadius:渐变半径,仅当 android:type="radial" 时有效
- android:useLevel:一般为 false,当 Drawable 作为 StateListDrawable 使用时为 true
- android:type:渐变的类别,有 linear 线性渐变、radial 径向渐变、sweep 扫描线渐变三种,默认为 线性渐变
- <solid>:表示 纯色填充,通过 android:color 指定 填充的颜色
-
<stroke>:Shape 的描边,有如下属性
- android:width:描边宽度
- android:color:描边颜色
- android:dashWidth:组成虚线的线段的宽度
- android:dashGap:组成虚线的线段之间的间隔
- <padding>:表示包含当前 Shape 的 View 的空白,有四个属性, android:left、android:right、android:top、android:bottom。
- <size>:shape 的大小,有两个属性:android:width 和 android:height,分别表示 shape 的固有宽/高,但是作为 View 的背景时,仍会被拉伸或者缩小为 View 的大小
3.LayerDrawable
对应的 XML 标签是 <layer-list>,表示一种层次化的 Drawable 集合。一个 layer-list 可以包含多 个item,每一个 item 表示一个 Drawable。
Layer-list 有层次的概念,下面的 item 会覆盖上面的 item,即会分层与叠加。
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@[package:]drawable/drawable_resource"
android:id="@[+][package:]id/resource_name"
android:bottom="dimenison"
android:left="dimenison"
android:right="dimenison"
android:top="dimenison" />
</layer-list>
4.StateListDrawable
对应于 <selector> 标签,也是表示 drawable 集合,每个 Drawable 对应着 View 的一种状态,这样系统会根据 View 的状态来选择合适的 Drawable。
主要用于设置可单击的 View 的背景。
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:constantSize=["true"|"false"]
android:dither=["true"|"false"]
android:variablePadding=["true"|"false"]>
<item
android:drawable="@[package:]drawable/drawable_resource"
android:state_pressed=["true"|"false"]
android:state_foucused=["true"|"false"]
android:state_hoverd=["true"|"false"]
android:state_selected=["true"|"false"]
android:state_checkable=["true"|"false"]
android:state_checked=["true"|"false"]
android:state_enabled=["true"|"false"]
android:state_activated=["true"|"false"]
android:state_window_focused=["true"|"false"] />
</selector>
相关属性介绍:
- android:constantSize:固有大小是否不随着其状态的改变而改变,因为状态的改变会导致 StateListDrawable 切换到具体的 Drawable,而不同的 Drawable 有不同的固有大小,true 表示 固有大小保持不变,此时它的固有大小是内部所有 Drawable 的固有大小的最大值。默认值为 false
- android:dither:是否开启抖动效果。
- android:variablePadding:padding 是否随着其状态的改变而改变。类似 constantSize 属性。
- 状态相关
- android:state_pressed:按下状态,此时按下尚未松开
- android:state_focused:获取了焦点
- android:state_selected:用户选择了 view
- android:state_checked:用户选中了 view
- android:state_enabled:view 当前处于可用状态
5.LevelListDrawable
对应于 <level-list> 标签,同样表示 Drawable 集合,集合中的每个 Drawable 都有一个 等级level 的概念,根据不同等级,切换对应的 Drawable。
每个 item 对应一个 Drawable,并且由 android:maxLevel 和 android:minLevel 指定对应的等级范围。
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/drawable_resource"
android:maxLevel="integer"
android:minLevel="integer"/>
</selector>
6.TransitionDrawable
对应于 <transition> 标签,用于实现两个 Drawable 之间的淡入淡出的效果。
<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@[package:]drawable/drawable_resource"
android:id="@[+][package:]id/resource_name"
android:bottom="dimenison"
android:left="dimenison"
android:right="dimenison"
android:top="dimenison"/>
</transition>
通过将 TransitionDrawable 设置为 view 的背景,通过view 的 startTransition 和 reverseTransition 方法实现淡入淡出的效果以及其逆过程。
7.InsetDrawable
对应于 <inset> 标签,可以将其他 Drawable 内嵌到自己当中,并可以在四周留出一定的间距。当一个 View 希望自己的背景比自己的实际区域小的时候,可以采用 InsetDrawable 来实现。
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/drawable_resource"
android:insetBottom="dimension"
android:insetLeft="dimension"
android:insetRight="dimension"
android:insetTop="dimension">
</inset>
8.ScaleDrawable
对应于 <scale> 标签,根据自己的等级 level 将指定的 Drawable 缩放到一定比例。
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/drawable_resource"
android:scaleGravity=["top"|"bottom"|"left"|"right"|"center_vertical"|"fill_vertical"|"center_horizontal"|"fill_horizontal"|"center"|"fill"|"clip_vertical"|"clip_horizontal"]
android:scaleHeight="percentage"
android:scaleWidth="percentage">
</scale>
定义的缩放比例越大,那么内部 Drawable 看起来越小。
除了定义上述 Drawable,还需要设置等级。
ScaleDrawable scaleDrawable = (ScaleDrawable) imageView.getBackground();
caleDrawable.setLevel(1);
9.ClipDrawable
对应于 <clip> 标签,根据自己当前等级 Level 来裁剪另一个 Drawable,裁剪方向可以通过 android:clipOrientation 和 android:gravity 共同控制。
<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
android:clipOrientation=["horizontal"|"vertical"]
android:drawable="@drawable/drawable_resource"
android:gravity=["top"|"bottom"|"left"|"right"|"center_vertical"|"fill_vertical"|"center_horizontal"|"fill_horizontal"|"center"|"fill"|"clip_vertical"|"clip_horizontal"]>
</clip>
仍需要在代码中设置 ClipDrawable 的等级。等级的范围是 0~10000,0 表示 完全裁剪,10000 表示不裁剪。
ClipDrawable clipDrawable = (ClipDrawable) ivLevei.getBackground();
clipDrawable.setLevel(7000);
自定义 Drawable
通常下,没有必要自定义 Drawable,因为自定义的 Drawable 无法在 xml 中使用。
核心方法:draw(),setAlpha(),setColorFilter(),sgetOpacity()。
当自定义的 Drawable 由固有大小时最好重写 getInntrinsicWidth 和 getintrinsicHeight ,因为二者会影响到 view 的 wrap_content 布局。
内部大小不等于 Drawable 的实际区域大小,Drawable 实际区域大小可以通过 getBounds 方法得到,一般个它的 View 的尺寸相同。