来自android开发艺术探索
Drawable:可拉伸的,表示一种可以在Canvas上进行绘制的抽象概念,常见的颜色和图片都是一个Drawable
Drawable的优点:使用简单,比自定义View成本低,非图片类型的Drawable占用空间小,有助于减小apk大小
什么是Drawable
表示一种图像的概念,可以是图片,也可以通过颜色构建一个Drawable,实际中,Drawable常常被用作为View的背景,Drawable一般通过XML文件来定义,也可以通过代码。
在Android中,Drawable是一个抽象类,是所有Drawable的基类。
public abstract class Drawable {
// 获取内部宽高,由子类重写
public int getIntrinsicWidth() {
return -1;
}
public int getIntrinsicHeight() {
return -1;
}
}
Drawable的内部宽高就是图片的宽高,但是内部宽高不等同于它的大小,Drawable没有大小的概念,在当作view的北京的时候可以被拉伸至View的大小,颜色形成的Drawable没有内部宽高的概念。
Drawable的分类
1.BitmapDrawable
表示一张图片,在res/drawable目录通过XML自定义一个Drawable
<?xml version="1.0" encoding="utf-8"?>
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/app_dvr_icon" // 图片id
android:antialias="true" // 是否开启抗锯齿功能
android:dither="true" // 是否开启抖动效果
android:filter="true" // 是否开启过滤效果
android:alpha="0.5" // 透明度
android:gravity="bottom|top" // 定位
android:mipMap="true" // 纹理映射
android:tileMode="clamp"> // 平铺模式
</bitmap>
另一种.9g格式的图片,NinePatchDrawable可以自动根据宽高进行相应的缩放并保证不失真,使用和BitmapDrawable相同,可以通过XML描述:
<?xml version="1.0" encoding="utf-8"?>
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/app_dvr_icon"
android:dither="true">
</nine-patch>
2.ShapeDrawable
通过颜色来构造的图形,shape标签实际上创建的是GradientDrawable
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"> // 图形形状
<corners // shape的四个角的角度
android:radius="20dp"
android:topLeftRadius="20dp">
</corners>
<gradient // 与solid互斥,渐变效果
android:angle="20"
android:centerX="20"
android:useLevel="true">
</gradient>
<padding // 表示空白,表示包含它的View的空白
android:bottom="20dp"
android:left="20dp">
</padding>
<size // shape的大小
android:width="20dp"
android:height="20dp">
</size>
<solid // 纯色填充
android:color="@color/blackColor">
</solid>
<stroke // shape的描边
android:width="20dp"
android:dashGap="20dp">
</stroke>
</shape>
3.LayerDrawable
对应的XML标签是<layer-list>,表示一种层次化的Drawable集合,将不同的Drawable放置在不同层上从而达到一种叠加后的效果:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/app_dvr_icon"
android:id="@+id/nihao"
android:top="20dp"
android:left="20dp">
</item>
<item
......>
</item>
</layer-list>
一个layer-list中可以包含多个item,每个item表示一个Drawable,layer-list默认所有的Drawable都会被压缩至view的大小,下面的item会覆盖上面的item,可以实现一些叠加的效果。
4.StateListDrawable
对应的标签是<selector>,也表示Drawable的集合,每个Drawable代表View的一种状态,系统根据View的状态从selector总选择合适的item,即Drawable,从上往下的顺序查找,主要用来设置可以单击的View的背景,如Button:默认的item都应该放到selector的最后一条并且不附带任何状态,当上面的item无法匹配时,系统会选择默认的item,因为不附带状态,可以匹配任何状态
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:constantSize="true" // 固有大小是否随着状态的改变而改变
android:dither="true"
android:variablePadding="true"> // padding是否随着状态的改变而改变
<item android:drawable="@drawable/app_weather_pressed" android:state_selected="true" />
<item android:drawable="@drawable/app_weather_pressed" android:state_pressed="true" />
<item android:drawable="@drawable/app_weather_normal" android:state_focused="true" /> // view的各种状态
<item android:drawable="@drawable/app_weather_normal" />
</selector>
5.LevelListDrawable
对应XML标签是<level-list>,同样表示一个Drawable的集合,每个Drawable有一个等级的概念,根据不同等级,LevelListDrawable切换为对应的Drawable,语法如下:
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/app_dvr_icon"
android:maxLevel="7" // 最大等级
android:minLevel="5"> // 最小等级
</item>
<item
android:drawable="@drawable/app_dvr_icon"
android:maxLevel="4"
android:minLevel="1">
</item>
</level-list>
在最大最小等级之间的等级对应此item中的Drawable,当作为View的背景时,通过Drawable的setLevel设置等级从而切换具体的Drawable,作为ImageView的前景时,通过ImageView.setImageLevel切换Drawable
6.TransitionDrawable
实现两个Drawable之间的淡入淡出效果
<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/app_dvr_icon">
</item>
<item
android:drawable="@drawable/app_dvr_normal">
</item>
</transition>
TextView view = (TextView) findViewById(R.id.text_view);
TransitionDrawable drawable = (TransitionDrawable) view.getBackground();
drawable.startTransition(1000);
7.InsertDrawable
可以将其他Drawable内嵌到自己当中,并可以在四周留出一定的间距,当一个View希望自己的背景比自己的实际区域小时,可以采用InserDrawable,LayerDrawable也可以实现
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="@dimen/abc_control_inset_material" // 表示四个边内凹的大小
android:insetTop="@dimen/abc_control_inset_material"
android:insetBottom="@dimen/abc_control_inset_material"
android:insetRight="@dimen/abc_control_inset_material">
<selector>
<item android:state_checked="false" android:state_pressed="false">
<layer-list>
<item android:drawable="@drawable/abc_textfield_default_mtrl_alpha" />
<item android:drawable="@drawable/abc_spinner_mtrl_am_alpha" />
</layer-list>
</item>
<item>
<layer-list>
<item android:drawable="@drawable/abc_textfield_activated_mtrl_alpha" />
<item android:drawable="@drawable/abc_spinner_mtrl_am_alpha" />
</layer-list>
</item>
</selector>
</inset>
8.ScaleDrawable