1,概念
Drawable可以在Canvas上进行绘制。
一般用作View的背景来使用。此时Drawable被拉做View的大小。
最常见的颜色和图片都可以是一个Drawable。
1)优点
使用简单:比自定义View成本低。
占用空间校:非图片类型的Drawable占用空间小,可以减小apk的大小。
2)优化
①在onDraw最终不用创建新的局部对象。
onDraw被频繁调用,创建了新的局部对象后,会一瞬间产生大量的临时对象,这样占用内存并导致系统频繁gc。
②onDraw中不做耗时任务。
2,分类
1)BitmapDrawable
表示一张图片。
①属性
android:src
--图片的资源id
android:antialias
--是否开启图片抗锯齿功能。开启后让图片变平滑,但降低清晰度。
android:dither
--是否开启抖动效果。当图片像素配置和手机屏幕的像素配置不一致时,可以让高质量的图片在低质量的屏幕上还能保持较好的显示效果,不至于失真。
android:filter
--是否开启过滤效果。当图片尺寸被拉伸或者压缩时,可保持较好的显示效果。
android:gravity
--图片小于容器尺寸,可通过此项定位图片。
--top、bottom、left、right 不改变图片大小。
--center_vertical、fill_vertical、center、fill
--clip_vertical 竖直方向的裁剪
android:mipMap
--图像处理技术:纹理映射。默认为false
android:tileMode
--平铺模式
--disabled 关闭此项,默认值
--clamp(图片四周的像素会扩展到周围区域)、repeat、mirror 开启平铺模式,gravity属性将失效。
2)ShapeDrawable
通过颜色构造的图片。由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="@color/white" /><!-- 填充的颜色 -->
<!-- 大小 -->
<size
android:width="1000dp"
android:height="50dp" /><!-- 宽度和高度 -->
<!-- 间隔 -->
<padding
android:bottom="2dp"
android:left="5dp"
android:right="5dp"
android:top="2dp" /><!-- 各方向的间隔 -->
<!-- 圆角 -->
<corners
android:radius="90dp"
android:topLeftRadius="20dp"
android:topRightRadius="20dp"
android:bottomLeftRadius="20dp"
android:bottomRightRadius="20dp"/>
<!-- 描边 -->
<stroke
android:width="2dp"
android:color="@color/blue"
android:dashWidth="0dp"
android:dashGap="0dp"/><!-- dashWidth横线的宽度;dashGap表示之间隔开的距离 -->
</shape>
①shape
形状:rectangle、oval、line、ring。其中line、ring要通过stroke标签指定线的宽度和颜色)。
②corners
其中radius优先级最低。
③gradient
与solid标签互斥。
渐变效果填充。
属性:
–android:angle:
渐变的角度,默认为0,值应为45的倍数,0表示从左到右,90表示从下到上。
–android:centerX
渐变的中心点的坐标。
–android:startColor
渐变的起始色、中间色(centerColor)、结束色(endColor).
–android:gradientRadius
渐变半径,仅当android:type=”radial”时有效。
–android:useLevel
当Drawable作为StateListDrawable使用时为true.
–android:type
渐变类别。如:linear(线性渐变,默认)、radial(径向渐变)、sweep(扫描线渐变)
④solid
表示纯色填充。
⑤stroke
–android:width
描边的粗细。
–android:color
描边的颜色。
–android:dashWidth
描边组成虚线的线段的宽度。
–android:dashGap
描边虚线的线段之间的间隔。
⑥padding
表示包含drawable的View的空白
⑦size
shape的大小。通过该标签指定宽高后,getIntrinsicWidth就会返回该值,否则返回-1.
3)LayerDrawable
通过对应的XML<layer-list>
,表示层次化的Drawable集合,通过将不同的Drawable放置在不同的层上面表达叠加后的效果。
举例一:
绘制图片背景,只保留顶部的边线。
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:right="-5dp"
android:left="-5dp"
android:bottom="-5dp">
<shape>
<solid android:color="@android:color/transparent"/>
<stroke
android:width="5dp"
android:color="@color/colorTheme"/>
</shape>
</item>
</layer-list>
举例二:文本输入框
4)StateListDrawable
对应<selector>
标签,表示Drawable集合,每个Drawable都对应着View的一种状态。
主要用于可点击的View的背景。
举例:背景选择器
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:constantSize=["true"|"flase"]
android:dither=["true"|"flase"]
android:variablePadding=["true"|"flase"]>
<!-- 默认时的背景图片 -->
<item android:drawable="@drawable/btn_refresh"/>
<!-- 单击时的背景图片 -->
<item android:state_pressed="true" android:drawable="@drawable/btn_refresh_click" />
<!-- 程序是否在前台 -->
<item android:state_window_focused="false" android:drawable="@drawable/btn_refresh"/>
<!--选中时的图片背景-->
<item android:state_selected="true" android:drawable="@drawable/btn_refresh" />
<!--获得焦点时的图片背景-->
<item android:state_focused="true" android:drawable="@drawable/btn_refresh" />
<!-- 光标悬停 -->
<item android:state_hovered="true" android:drawable="@drawable/btn_refresh" />
<!-- -->
--android:state_checked 表示拥护选中了View,适用于CheckBox这类在选中和非选中状态之间进行切换的View.
--android:state_enabled 表示当前处于可用状态
</selector>
①constantSize
StateListDrawable的固有大小是否随着状态改变。true表示保持不变。默认为false.
②dither
是否开启抖动效果。
开启会让图片在低质量屏幕扔能显示。
③variablePadding
StateListDrawable是否随着其状态改变padding。true表示会随之改变。默认值为false。
④注意
是从上到下读取图片状态,如果把
放在最前面,后面的可能不起作用。
<item android:drawable="@drawable/btn_refresh"/>
⑤应用
CheckBox的背景图片/textColor设置为StateListDrawable可以进行点击切换动画。如下:
<item android:state_checked="true" android:drawable="@drawable/btn_click" />
<item android:state_pressed="true" android:drawable="@drawable/btn_click" />
<item android:state_checked="false" android:drawable="@drawable/btn_unclick" />
<item android:state_checked="true" android:color="@color/btn_click" />
<item android:state_pressed="true" android:color="@color/btn_click" />
<item android:state_checked="false" android:color="@color/btn_unclick" />
5)LevelListDrawable
LevelListDrawable对应于<level-list>
标签,是一个Drawable集合,集合中每一个Drawable都有一个登记的概念。根据不同等级,切换对应的Drawable。
如下所示,每个item表示一个Drawable,对应其等级范围。
<?xml versionn="1.0" encoding="utf-8"?>
<level-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/icon1"
android:maxLevel="integer"
android:minLevel="integer"/>
</level-list>
使用时,通过Drawable的setLevel方法设置不同等级(0~10000),切换Drawable。
或通过ImageView的setImageLevel方法来切换。
6)TransitionDrawable
对应于<transition>
标签,用于实现两个Drawable之间的淡入淡出效果。
<?xml versionn="1.0" encoding="utf-8"?>
<transition
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/icon1"
android:id=""
android:top="dimension"
android:right="dimension"
android:bottom="dimension"
android:left="dimension"/>
</transition>
相应的View的background设置为此Drawable。
最后通过TransitionDrawable 的startTransition和reverseTransition方法来实现淡入淡出的效果以及你过程。
TextView textView = (TextView) findViewById(R.id.tv_transition);
TransitionDrawable drawable = (TransitionDrawable) textView.getBackground();
drawable.startTransition(1000);
7)InsetDrawable
对应于<inset>
标签,用于一个View希望比自己的实际区域小的时候。LayerDrawable也可以实现这种效果。
<?xml versionn="1.0" encoding="utf-8"?>
<inset
xmlns:android="http://schemas.android.com/apk/res/android"
android:insetTop="15dp"
android:insetRight="15dp"
android:insetBottom="15dp"
android:insetLeft="15dpn">
<shape android:shape="rectangle">
<solid android:color="#ff0000"/>
</shape>
</inset>
View v_scale = findViewById(R.id.scale);
ScaleDrawable sacleDrawable = (ScaleDrawable )v_scale.getBackground();
sacleDrawable setLevel(1);
8)ScaleDrawable
对应<scale>
标签,根据等级(getLevel方法,范围为0-10000)指定Drawable缩放比例。
等级越大,表示裁剪的区域越小。
level=0,表示ScaleDrawable不可见(完全裁剪),这是默认值。
level=10000,不裁剪。
<?xml versionn="1.0" encoding="utf-8"?>
<scale
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="#drawable/icon1"
android:scaleGravity=["top" | "bottom" | "left" | "right" | "center_vertical" | "fill_vertical" | "center" | "fill" | "clip_vertical"]
android:scaleHeight="20%"
android:scaleWidth="20%"/>
9)ClipDrawable
对应于<clip>
标签,根据等级裁剪另一个Drawable。裁剪方向由android:clipOrientation和android:gravity控制。
<?xml versionn="1.0" encoding="utf-8"?>
<clip
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="#drawable/icon1"
android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" | "fill_vertical" | "center" | "fill" | "clip_vertical"]
android:clipOrientation=["horizontal" | "vertical"]/>
gravity属性中:
–top 将内部Drawable放在容器顶部。如果为竖直裁剪,从底部开始裁剪。
–center_vertical 如果为竖直裁剪,从上下同时开始裁剪。
–fill_vertical 填充容器,只有等级为0(不可见)的裁剪行为。
ImageView clip = (ImageView)findViewById(r.id.clip);
ClipDrawable clipDrawable = (ClipDrawable) clip.getDrawable();
clipDrawable.setLevel(5000);
3,自定义Drawable
public class CustomDrawable extends Drawable{
private Paint mPaint;
public CustomDrawable(int color){
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(color);
}
@Override
public void draw(Canvas canvas){
finnal Rect r = getBounds();//获得实际区域大小,一般和View尺寸相同
float cx = r.exactCenterX();
float cy = r.exactCenterY();
canvas.drawCircle(cx,cy,Math.min(cx,cy),mPaint);
}
@Override
public void setAlpha(int alpha){
mPaint.setAlpha(alpha);
invalidateSelf();
}
@Override
public void setColorFilter(ColorFilter cf){
mPaint.setColorFilter(cf);
invalidateSelf();
}
@Override
public void getOpacity(){
return PixelFormat.TRANSLUCENT;
}
}