Drawable简介
提到Drawable,第一反应肯定是存放图片的位置,实际上,Drawable并不仅仅指图片。它可以理解为一种图片的概念,比如颜色填充,也可以理解为一种图片。
Drawable类是一个抽象类,它有BitmapDrawable,ShapeDrawable,LayerDrawable,StateListDrawable等常用子类。
BitmapDrawable
BitmapDrawable就是一张图片,通过src属性定义指向的图片资源,然后对该图片进行相关设置主要属性如下:
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/ic_launcher"
android:gravity="bottom"//设定图片在容器中的位置,默认值为fill,在水平和竖直方向填充容器
android:antialias="true"//设置抗锯齿
android:tint 给图片着色,比如图片本来是黑色的,着色后可以变成白色
android:tintMode 着色模式,也是API Level 21(Android 5.0)才添加的属性
android:alpha 设置图片的透明度,取值范围为0.0~1.0之间,API Level最低要求是11,即Android 3.0
android:filter="true"//开启过滤效果
android:dither="true"//开启抖动效果
android:tileMode="clamp"//设置平铺方式,disable,clamp,repeat,mirror
>
</bitmap>
//使用代码进行动态设置:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
BitmapDrawable bitmapDrawable = new BitmapDrawable(bitmap);
bitmapDrawable.setTileModeXY(Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
bitmapDrawable.setAntiAlias(true);
bitmapDrawable.setDither(true);
除了针对常见图片的BitmapDrawable之外,NinePatchDrawable对应的是.9图片,用法同BitmapDrawable一样,根标签是nine-patch
ColorDrawable
ColorDrawable用纯色填充一块区域,使用也最简单,只有一个属性,color:
<color xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/colorBlack">
</color>
//代码设定:
ColorDrawable colorDrawable = new ColorDrawable(0xffff0000);
//使用颜色:
mImageView.setBackground(new ColorDrawable(0xffff0000));
mImageView.setBackgroundColor(Color.argb(255,00,255,00));
Android中对颜色的设定采用ARGB模式,xml中可以不指定alpha值,但是在代码中使用十六进制数值设置颜色时,必须制定alpha值,否则默认为0x00,全透明,是看不到颜色的。
GradientDrawable(ShapeDrawable)
GradientDrawable表示一个渐变区域,可以实现线性渐变、发散渐变、和平铺渐变。它的主要属性如下:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line">//设置Shape形状,rectangle(矩形),oval(椭圆),line(直线),ring(圆形)四个可选值
<!-- 下面的属性只有在android:shape="ring时可用:
android:innerRadius 尺寸,内环的半径。
android:innerRadiusRatio 浮点型,以环的宽度比率来表示内环的半径,
android:thickness 尺寸,环的厚度
android:thicknessRatio 浮点型,以环的宽度比率来表示环的厚度,例如,如果android:thicknessRatio="2",
android:useLevel boolean值,如果当做是LevelListDrawable使用时值为true,否则为false. "-->
<corners //只有rectangle有效,用来设置四个角的圆角半径
android:radius="50px"//对四个角统一设置,优先级较低,会被以下属性覆盖
android:topLeftRadius="40dp"
android:topRightRadius="40dp"
android:bottomLeftRadius="40dp"
android:bottomRightRadius="40dp"/>
<gradient//渐变效果
android:angle="45"//渐变的方向角度,必须为45的倍数,默认为0
android:centerX="100"//渐变中心点X坐标
android:centerY="250"
android:startColor="@color/colorBlack"//渐变起始色
android:centerColor="@color/colorDarkGreen"//渐变中间颜色
android:endColor="@color/colorWhite"//结束颜色
android:gradientRadius="50dp"//渐变半径,只有type值为radial时有效
android:type="linear"//渐变类型,有Linear(线性),radial(径向),sweep(扫描线)三种。默认为线型渐变
android:useLevel="false"/>//一般为false,只有当Drawable作为StateListDrawable使用才设置true
<solid//纯色填充,与gradient互斥
android:color="@color/colorDarkGreen"/>
<stroke//Shape描边效果
android:width="5dp"//描边宽度
android:color="@color/colorLightRed"
android:dashWidth="15dp"//线条长度
android:dashGap="5dp"/>//线条间距
<padding//设置内边距
android:left="5dp"
android:right="5dp"
android:bottom="5dp"
android:top="5dp"/>
<size//设置尺寸。Drawable本身是没有尺寸概念的,使用getIntrinsicWidth/Height获取到的值是-1。通过Size设定Drawable固有尺寸。
但是作为背景的时候,Shape仍然会拉伸为适合view的大小
android:width="200dp"
android:height="200dp"/>
</shape>
LayerDrawable
LayerDrawable包含多个item,每个item表示一个drawable,LayerDrawable将所包含的item放置在不同的层次上,第一个item在最底层,依次向上叠加:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:left="2dp"
android:top="4dp">
<shape>
<solid android:color="@android:color/darker_gray" />
<corners android:radius="10dp" />
</shape>
</item>
<item
android:bottom="4dp"
android:right="2dp">
<shape>
<solid android:color="#FFFFFF" />
<corners android:radius="10dp" />
</shape>
</item>
</layer-list>
item子节点可以直接定义一个Drawable,也可以使用android:drawable属性来引用一个Drawable,layer-list没有属性节点,只包含Item子节点。Item节点属性除了android:drawable,还有android:top/left/right/bottom用来设定各个方向的偏移距离
StateListDrawable
StatelistDrawable也是一个Drawable集合,每个Drawable对应View的一种状态,只要用在设置View的背景。它使用selector标签:
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:constantSize="true" //默认为false。因为状态改变的时候会切换到不同的Drawable,大小也是不同的,设置为true表示尺寸固定不变
android:dither="true"
android:variablePadding="true"//默认为false,表示padding不随着状态的改变而变化。
android:enterFadeDuration="500"//状态改变时切入的动作事件,ms
android:exitFadeDuration="500">
<item
android:drawable="@color/colorBlack"//指定Drawable资源,也可以是color
android:state_pressed="true"//按下状态
android:state_focused="true"//获取到焦点
android:state_hovered="true"//API14加入,true表示鼠标在其上滑动
android:state_selected="true"//选择了view
android:state_checkable="true"//可选择状态。类似于enable,它用来设置CheckBox等可勾选的控件
android:state_checked="true"//是否选中状态
android:state_enabled="false"//是否可用状态。通常只设置false
android:state_activated="true"/是否被激活状态,API Level 11及以上才支持,可通过代码调用控件的setActivated(boolean)方法设置是否激活该控件
android:state_window_focused="true"/>//当前窗口是否获取焦点。比如弹出对话框就会失去焦点
</selector>
系统会根据View的当前状态从selector中选择对应的item,选择的时候会从上向下一直找到第一条匹配的item,通常会设置一个默认的item放在最后,不设置任何的状态。这样当系统在上边的item中找不到对应的状态时,就会选择最后一个默认的item,它不附带任何状态,可以匹配给所以状态。
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 当前窗口失去焦点时 -->
<item android:color="@android:color/black" android:state_window_focused="false" />
<!-- 不可用时 -->
<item android:color="@android:color/background_light" android:state_enabled="false" />
<!-- 按压时 -->
<item android:color="@android:color/holo_blue_light" android:state_pressed="true" />
<!-- 被选中时 -->
<item android:color="@android:color/holo_green_dark" android:state_selected="true" />
<!-- 被激活时 -->
<item android:color="@android:color/holo_green_light" android:state_activated="true" />
<!-- 默认时 -->
<item android:color="@android:color/white" />
</selector>
//在控件中使用Drawable
<Button
android:id="@+id/btn_default"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:background="@drawable/bg_btn_selector"
android:text="默认按钮"
android:textColor="@color/text_btn_selector" />
LevelListDrawable
LevelListDrawable也是一系列Drawable集合,它通过Level来匹配item。
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@color/colorBlack"
android:maxLevel="10000"
android:minLevel="0"/>
</level-list>
item子节点除了指定Drawable之外,只有两个属性android:maxLevel指定最高Level(10000),android:minLevel指定最低Level(0),在这两个值中间就会匹配该item。匹配的时候也是从上向下,直到匹配到一条合适的item 。所以,通常只需要指定maxLevel就可以了,将item按maxLevel从小到大依次排列下来。
Level的设置使用Drawable的setLevel方法来设定。如果是作为ImageView的前景,也可以通过ImageView的setImageLevel来设定。
TransitionDrawable
transition其实是继承自layer-list的,只是,transition只能管理两层drawable,另外提供了两层drawable之间切换的方法,切换时还会有淡入淡出的动画效果。示例代码如下:
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/on" />
<item android:drawable="@drawable/off" />
</transition>
然后在控件中指定背景:
<Button
android:id="@+id/btn1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/transition_drawable"
/>
transition标签生成的Drawable对应的类为TransitionDrawable,要切换时,需要主动调用TransitionDrawable的startTransition()方法,参数为动画的毫秒数,也可以调用reverseTransition()方法逆向切换。
Button mButton = (Button) findViewById(R.id.btn1);
TransitionDrawable transitionDrawable = mButton.getBackground();
transitionDrawable.startTransition(500); //正向切换,即从第一个drawable切换到第二个
transitionDrawable.reverseTransition(500); //逆向切换,即从第二个drawable切换回第一个
InsetDrawable
InsetDrawable使用<inset>标签,可以将指定的Drawable内嵌到自己当中,特殊的是它可以设置四周的间距,作为背景时,设定值为背景与view边框的距离,用layerList同样可以实现。
android:drawable 指定drawable资源,如果不设置该属性,也可以定义drawable类型的子标签
android:visible 设置初始的可见性状态,默认为false
android:insetLeft 左边距
android:insetRight 右边距
android:insetTop 顶部边距
android:insetBottom 底部边距
android:inset 设置统一边距,会覆盖上面四个属性,但API Level要求为21,即Android 5.0
ScaleDrawable
ScaleDrawable使用<scale>标签,它可以对指定的drawable进行缩放。它的scaleGravity属性作用同BItmap一样。另外还有两个特殊属性,scaleHeight和scaleWidt指定宽和高的缩放比例,接收百分比数值。需要注意的是,ScaleDrawable缩放效果不仅仅受scaleHeight和scaleWidth影响,还要指定Level。默认的Level为0,这时候ScaleDrawable是不会绘制的。下面来看一个例子:
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/ic_launcher"
android:scaleGravity="center"
android:scaleHeight="30%"//实际大小约为70%
android:scaleWidth="30%"
android:level="1"/>//API 24以上才支持
//在控件中使用:这时候是看不到图片的,没有设置Level,图片不会绘制出来
<ImageView
android:id="@+id/scaleimg"
android:src="@drawable/scaledraw"
android:layout_width="150dp"
android:layout_height="150dp"/>
//设置Level:
mScaleImageView.setImageLevel(1);
注意的是,Level对缩放比例的影响,Level值越大,Drawable就越大,如果设置为10000(Level最大值),那么不管缩放比例设置多少,都不会进行缩放。而scaleHeight和scaleWidth相反,值越大,Drawable越小。
ClipDrawable
ClipDrawable用来对Drawable进行裁剪,它也是根据Level来决定裁剪范围,10000表示不裁剪,0表示全部裁剪,就看不到了。裁剪的方向通过clipOritation来设置vertical和horizontal,除此之外还有一个Gravity属性,它和clipOritation一起决定了裁剪方式。
Gravity有以下取值:
top: Drawable放在容器顶部,竖直裁剪的时候从底部开始
bottom:Drawable放在容器底部,竖直裁剪时从顶部开始
left:默认值。Drawable放在容器左边,水平裁剪时从右边开始
right:放在右边,水平裁剪从左边开始
center_vertical:Drawable竖直居中,不改变大小,竖直裁剪从上下同时开始
fill_vertical:竖直方向填充容器。竖直裁剪的时候,只有clipDrawable的level为0,才有裁剪行为
center_horizontal:水平居中,不改变大小,水平裁剪从左右同时开始
fill_horizontal:水平填充,水平裁剪只有当clipDrawable的level为0,才有裁剪行为
center:水平和垂直居中,竖直方向上下,水平方向左右同时裁剪
fill:水平和竖直方向填充容器,只有当clipDrawable的level为0,才有裁剪行为
其他标签
-
rotate
<rotate>标签用来控制Drawable的旋转,主要用以下属性:android:drawable 指定drawable资源,如果不设置该属性,也可以定义drawable类型的子标签
android:fromDegrees 起始的角度度数
android:toDegrees 结束的角度度数,正数表示顺时针,负数表示逆时针
android:pivotX 旋转中心的X坐标,浮点数或是百分比。浮点数表示相对于drawable的左边缘距离单位为px,如5; 百分比表示相对于drawable的左边缘距离按百分比计算,如5%; 另一种百分比表示相对于父容器的左边缘,如5%p; 一般设置为50%表示在drawable中心
android:pivotY 旋转中心的Y坐标
android:visible 设置初始的可见性状态,默认为false将一张图片旋转180度代码如下:
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/ic_arrow"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="180" />
rotate同样与Level有关。Level值从0-10000分别对应fromDegrees和toDegrees,比如Level设置5000就会旋转90度。因为level值默认为0,所以默认是不会旋转的,如果要旋转的话可以将android:fromDegrees直接设置180度,开始的状态就已经完成旋转了。
-
animation-list
<animation-list>用来将一系列drawable构建成帧动画。通过添加item子标签设置每一帧使用的drawable资源,以及每一帧持续的时间。示例代码如下:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item
android:drawable="@drawable/anim1"
android:duration="1000" />
<item
android:drawable="@mipmap/anim2"
android:duration="1000" />
<item
android:drawable="@mipmap/anim3"
android:duration="1000" />
</animation-list>
android:oneshot属性设置是否循环播放,设为true时,只播放一轮就结束,设为false时,则会轮询播放。
android:duration属性设置该帧持续的时间,以毫秒数为单位。
animation-list对应的Drawable类为AnimationDrawable,要让动画运行起来,需要主动调用AnimationDrawable的start()方法。另外,如果在Activity的onCreate()方法里直接调用start()方法会没有效果,因为view还没有初始化完成是播放不了动画的。
-
animation-rotate
rotate标签只是将原有的drawable转个角度变成另一个drawable,它是静态的。而animated-rotate则会让drawable不停地做旋转动画。
animated-rotate可设置的属性只有四个:
android:drawable 指定drawable资源,如果不设置该属性,也可以定义drawable类型的子标签
android:pivotX 旋转中心的X坐标
android:pivotY 旋转中心的Y坐标
android:visible 设置初始的可见性状态,默认为false
示例代码:
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/img_daisy"
android:pivotX="50%"
android:pivotY="50%"
android:visible="false" />