Android Drawable简单使用

本篇文章为《Android开发艺术探索》中Drawable篇的笔记,介绍的是一些常用的Drawable的使用,方便日后快速查阅。

本文一共介绍了9种Drawable,
第一组为单个Drawable,包含有:BitmapDrawable,ShapeDrawable;
第二组为组合Drawable,包含有:LayerDrawable,StateListDrawable,LevelListDrawable,TransitionDrawable;
第三组为辅助Drawable,包含有:InsetDrawable,ScaleDrawable,ClipDrawable

1,BitmapDrawable

  BitmapDrawable是一种简单的Drawable,它代表着一张图片。在实际中我们通常是直接引用图片,但这种方式比较单一,一些其他的操作如抗锯齿防抖动等无法显式进行控制,而使用BitmapDrawable则可以通过一些属性进行更加细腻化的调整。

 1.1 简单使用

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/ic_launcher"
    android:gravity="center_vertical"
    android:alpha="1"
    android:dither="true"
    android:antialias="true"
    android:tileMode="repeat">
bitmap>

  BitmapDrawable在xml中的使用是直接以bitmap为根目录,然后设置相应的属性即可。

 1.2 android:src

  该属性指向一个图片资源路径,是必须的属性。并且路径必须是在drawable中的具体图片,而不能是xml等图片资源。

 1.3 android:gravity

  left、right、top、center、bottom等,使用"|"组合多个参数,会使用该参数调整图片的位置。

 1.4 android:alpha

  图片的透明度,0~1,0为全透明,1不透明。

 1.5 android:dither 防抖动、android:antialias 抗锯齿
 1.6 android:tileMode

 平铺模式,该参数设置后会使gravity属性失效,取值为repeat、clamp,mirror、disabled。
  repeat:重复,当图片资源小于View控件时,采用重复图片的方式填充。可能会出现图片显示不完全的现象
  mirror:镜像,采用镜像图片来填充
  clamp:延伸,延伸图片边缘进行填充
  disabled:默认为disabled,没有效果

 * 宽高

  BitmapDrawable是具有宽高的,该宽高是src引用的图片的宽高,通过以下方法获取:

		BitmapDrawable drawable = (BitmapDrawable) mButton.getBackground();
        int height = drawable.getIntrinsicHeight();
        int width = drawable.getIntrinsicWidth();
     //   有些BitmapDrawable没有内在宽高,怎返回-1

  还有很多参数没有具体介绍,不过那些参数用的不是很多。也可以不通过xml进行设置,而是获取到BitmapDrawable对象后,直接在代码中动态设置。

2,ShapeDrawable

  ShapeDrawable是一种很常用的drawable,有四种shape可供选择:rectangle,oval,line,ring

 2.1 简单使用

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

	<size android:width="100dp" android:height="100dp"/>
    <solid android:color="#FFF"/>
    <stroke android:color="#FF00FF"
        android:width="3dp"/>
    <corners android:radius="5dp"/>

shape>

  ShapeDrawable以shape为根目录,通过内部的子标签进行控制显示的样式。

 2.2 根标签属性
  2.2.1 android:shape

  drawable的形状,四种状态可选。rectangle矩形,oval椭圆,line线性,ring环形(相当于两个同心圆)。

  2.2.2 android:innerRadius

  仅针对android:shape="ring"时生效,内圆半径。

  2.2.3 android:thickness

  仅针对android:shape="ring"时生效,圆环厚度,即外圆半径-内圆半径。设定内圆半径后可通过该属性控制外圆半径(外圆半径=innerRadius+thickness)

  2.2.4 android:innerRadiusRatio

  仅针对android:shape="ring"时生效,内圆半径占整个drawable宽度的比例,该属性只有在未设置内圆半径的时候才会生效,否则以innerRadius为准。默认值为9,代表内半径为drawable宽度的1/9。

  2.2.5 android:thicknessRatio

  仅针对android:shape="ring"时生效,厚度占整个drawable宽度的比例,该属性只有在未设置厚度的时候生效,否则以thickness为准。默认为3,代表厚度为drawable宽度的1/3。

  2.2.6 android:useLevel

  仅针对android:shape="ring"时生效,是否使用drawable的level对圆环进行缩放,从0到360度,默认为true,只有设置为 true时在单独的ShapeDrawable中才能正常显示圆环。

 2.3 子标签
  2.3.1 size

  该标签用于控制shape的大小,只有两个属性 android:width和android:height。由于ShapeDrawable是没有固定的大小的,它会适应View的大小。而通过该标签设置的size相当于原始大小,对shape的控制都是以此为基础的。
  例如size设置为宽高都是20dp的矩形,此时为正方形,在设置corner为10dp,此时为圆形。若是将该shape设置为一个宽高为100dp的View的背景,则此View此时的背景仍然为圆形,而不是圆角矩形。

  2.3.2 solid

  该标签用于控制填充颜色,只有一个属性android:color

  2.3.3 corners

  该标签控制四个角的圆角半径,有五个属性:android:radius同时设置4个角的圆角半径,android:topLeftRadius、topRightRadius、bottomLeftRadius、bottomRightRadius分别设置四个角的半径。
若是同时设置,则以分别设置的为准。

  2.3.4 stroke

  该标签设置边框,属性android:width设置边框的宽度,android:color设置边框的颜色。边框还可以设置为虚线,需要同时使用两个属性:android:dashGap两个虚线之间的距离,android:dashWidth每段虚线的长度。

  2.3.5 gradient

  该标签用于设置渐变填充,与solid一样,只是solid设置的为纯色。当设置该标签后,solid失效。

  • android:startColor 渐变开始颜色
  • android:centerColor 渐变中间颜色
  • android:endColor 渐变颜色
  • android:angle 渐变角度,取值范围[0,315],取值必须是45的倍数,也就是只能取8个值。取0时代表从左到右渐变,45时逆时针旋转45度,也就是从左下到右上。90时逆时针旋转90度,也就是从下到上。默认为0
  • android:centerX、centerY 渐变中心坐标,取值[0,1],代表着所占drawable的比例
  • android:type 渐变类型,三种取值 :linear线性渐变(默认),radial辐射渐变,从一个圆心逐渐向四周辐射渐变,sweep,扫描渐变,从drawable中心到右侧连线,然后按照顺时针进行旋转扫描渐变。
  • android:gradientRadius 渐变半径,只有type为radial时有效。

3,LayerDrawable

  LayerDrawable是一种组合的层级drawable,即内部可包含多个drawable。根标签为layer-list,内部包含多个item,每个item为一个drawable,下面的item覆盖在上面的item之上。

 3.1 简单使用

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@color/red" />
        shape>
    item>
    <item
        android:bottom="10dp"
        android:drawable="@drawable/map"
        android:left="10dp"
        android:right="10dp"
        android:top="10dp" />
layer-list>

 使用子标签item来引用drawable,item的属性如下:

  • android:top/left/bottom/right 代表当前item中的drawable的偏移量,就是drawable相对于view边缘的距离,如果view宽为100dp,item设置left和right都为10dp的话,该item的drawable显示大小则为80dp,造成背景没有view大的效果。
  • android:drawable 直接引用一个drawable,若是不设置该属性,可以直接在item的内部重新定义一个drawable。

4,StateListDrawable

  StateListDrawable是一种表示状态的Drawable,可以根据view不同的状态来显示不同的效果。根标签为selector,内部含有多个item,每个item可用来描述一种状态。
  当View的状态发生改变的时候,会从上到下进行匹配,若是匹配成功,则不会再继续向下匹配。因此,一般可以在最后面添加一个没有状态的item作为默认显示,当所有的状态都无法匹配时则会使用该item的drawable,类似于switch语句的最后一个default块。
  根标签为selector,内部含有多个item,每个item负责描述一种状态下的drawable。

 4.1 简单使用

<selector xmlns:android="http://schemas.android.com/apk/res/android"
    android:constantSize="true"
    android:dither="true"
    android:variablePadding="false">
    
    <item android:state_pressed="true" android:drawable="@color/red"/>
    <item android:state_pressed="false" android:drawable="@color/blue"/>

selector>

  上述的drawable描述为当view处于pressed状态时背景为红色,松开时显示为蓝色。

 4.2 根标签属性
  • android:dither 防抖动
  • android:constantSize 是否固有大小,false时在状态改变后会使用改变后的状态对应的drawable的大小。为true则大小不变,所有状态下的drawable大小都一样,该尺寸为所有drawable中的最大值。
  • enterFadeDuration 新状态进入的时间,单位ms
  • exitFadeDuration 旧状态淡出的时间,单位ms
 4.3 子标签item

  item有两种属性,一种是android:drawable,表示当前状态下的drawable背景。另一种是表示状态的属性,以下为常用的几种状态:

  • android:state_enabled 当前View是否可用
  • android:state_pressed 是否处于按压状态
  • android:state_checked 是否处于选中状态
  • android:state_selected 是否处于选中状态
  • android:state_focused 是否获取了焦点

5,LevelListDrawable

  LevelListDrawable与StateListDrawable很像,都是描述一组drawable,然后根据不同的情况显示不同的item。LevelListDrawable描述的是一组带有level的drawable,然后通过设置View的level来选择显示不同的drawable。
  根标签为level-list,内部可含有多个item,每一个item负责描述一个level范围内的drawable。

 5.1 简单使用

<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@color/red"
        android:maxLevel="100"
        android:minLevel="51" />
    <item
        android:drawable="@color/blue"
        android:maxLevel="50"
        android:minLevel="0" />
level-list>
	mButton = findViewById(R.id.btn);
    mButton.setOnClickListener(v -> {
        Drawable drawable = mButton.getBackground();
        drawable.setLevel(50);
    });

  LevelListDrawable比较简单,根标签的level-list没有其他属性,仅用来标识是一个LevelListDrawable。子标签item有三个属性,android:drawable用来指示所描述的drawable,android:maxLevel和android:minLevel用来确定所描述的level范围。当level发生变化时,就会从上到下进行范围匹配,匹配成功则使用此item指示的drawable。
  注意item的level范围可能会发生重叠,因为匹配是按照从上到下的,匹配到则返回不再向下继续匹配,因此发生重叠也没有问题。level的取值范围为[0,10000],默认为0。

6,TransitionDrawable

  TransitionDrawable是一种渐变的动画效果的drawable,使用transition作为根标签,内部包含两个item,可以实现两个item之间的渐变。

 6.1 简单使用

<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/level_drawable" />
    <item android:drawable="@color/blue" />
transition>
	mButton = findViewById(R.id.btn);
    mButton.setOnClickListener(v -> {
       TransitionDrawable drawable = (TransitionDrawable) mButton.getBackground();
        drawable.startTransition(1000);
        //drawable.reverseTransition(1000);
    });

  在需要渐变效果的时候,可以直接获取到drawable,然后调用startTransition来开始渐变。未变化前默认为第一个item,变化时是从第一个item逐渐变化到第二个item,然后停留在第二个item上。然后可以通过调用reverseTransition来从第二个item渐变到第一个item。
  item最多只能有两个,超过两个的话后面的将不会生效,只会取前两个。

  item标签的属性与LayerDrawable的item一样,android:left/right/top/bottom,都是上下左右的偏移量。

7,InsetDrawable

  InsetDrawable是一种辅助型的drawable,它主要是为其他drawable增加偏移属性。就像LayerDrawable和TransitionDrawable中Item的属性left/right/top/bottom一,可以造成drawable没有View大的效果。

 7.1 简单使用

<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:inset="10dp">

    <shape android:shape="rectangle">
        <solid android:color="@color/red" />
    shape>

inset>

 根标签是inset,其属性如下:

  • android:drawable 所引用的drawable
  • android:inset 偏移量,同时设置上下左右四个
  • android:insetLeft 设置左侧的偏移量
  • android:insetRight
  • android:insetTop
  • android:insetBottom

  InsetDrawable可以在根标签中的drawable属性中设置drawable,也可以直接在inset标签内部进行定义drawable。但是InsetDrawable只接受一个Drawable,也就是说若是在内部定义了Drawable后,根标签的drawable引用就会失效,同时若是内部定义了多个Drawable,则只有第一个才会生效。

8,ScaleDrawable

  ScaleDrawable和InsetDrawable一样,属于辅助型Drawable,InsetDrawable是为Drawable增加偏移属性,而ScaleDrawable则是对Drawable的缩放。

 8.1 简单使用

<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/map"
    android:level="1"
    android:scaleWidth="50%"
    android:scaleHeight="50%"
    android:scaleGravity="center">

    <shape android:shape="rectangle">
        <solid android:color="@color/red" />
    shape>

scale>

 根标签为scale,属性如下:

  • android:drawable 引用的drawable
  • android:scaleWidth 缩放宽度比例,单位为百分数,例如设置为40%,则代表缩放为原先的60%。
  • android:scaleHeight 缩放高度比例
  • android:scaleGravity 缩放重心,有多种参数可选,缩放时以重心所在位置进行缩放。
  • android:level 缩放时是以level为基准进行缩放,取值[0,10000]。这个属性是ScaleDrawable能否正常显示的基础,默认值为0,此时不能显示drawable。并且,前面的scaleWidth/Height设置的缩小比例只是能缩小的最大比例。比如:设置了40%,代表最大缩小40%,也就是变成原先的60%,在这个范围内,也可能缩小30%,20%,10%,甚至不缩小,这都是取决于level的。计算公式:(10000-level)/10000 * scaleWidth,也就是说若是设置的最大缩小比例为40%,而当前的level为5000的话,实际上只会缩小20%。

  level不仅可以在xml中的根标签中设置,也可以在代码中动态设置。同样的,和InsetDrawable一样,ScaleDrawable只缩放一个Drawable,若是在根标签内部定义了Drawable,则根标签属性drawable就会失效,若是在内部定义了多个drawable,则只会取第一个。

9,ClipDrawable

  ClipDrawable也是辅助型Drawable,它为Drawable提供的是裁剪功能。

 9.1 简单使用

<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:clipOrientation="vertical"
    android:drawable="@drawable/pic_4"
    android:gravity="center">
clip>
 9.2 android:clipOrientation

  剪切方向,有两个值可选,horizontal和vertical。horizontal代表着只剪切横向宽度,vertical代表只剪切纵向高度。可以使用"|"来将二者组合,即横向和纵向同时剪切。

 9.3 android:drawable 待剪切的drawable
 9.4 android:gravity

  剪切重心,有多种选择,可以使用"|"组合使用。left,center等,根据clipOrientation的设置会有不同的剪切表现。

  ClipDrawable比较简单,就只有这三个属性,因此剪切过后仍是矩形。注意的是ClipDrawable和前面提到的两种辅助型Drawable一样,ClipDrawable也只接受一个Drawable,若是在根标签内定义了其他Drawable的话,则根标签的drawable属性失效,若是定义了多个Drawable,则只要第一个才有作用。

  注意,剪切是基于原大小剪切的,也就是说剪切后,drawable的会比View小,导致View背景中会出现空白。剪切的比例是根据level来进行计算的,level的取值为[0,10000],若是设置level为4000,则代表着剪切到60%,则剪切后的图形为原先的40%。0则代表着完全剪切,则相当于不可见。

  注:CilpDrawable的剪切模式可以这样理解,首先根据level计算剪切比例,然后根据clipOrientation判断是横向还是纵向剪切,这两步后则可以得出剪切后的矩形大小,最后根据gravity来将这个矩形进行移动,最后显示这个矩形内部的图案,则这就是剪切后的结果。(这个过程只是为了方便理解而提的,并且也只适用于一些简单的gravity,比如left,right,top,bottom,center等)

你可能感兴趣的:(笔记,Drawable,Android)