android开发艺术(四)之 Drawable

1.Drawable基础知识

Drawable类是抽象类,是所有Drawable的基类,是一种在Canvas上进行绘制的对象
在这里插入图片描述
使用方式

  • 创建所需Drawable的根节点的xml,再通过@drawable/xxx引入布局中
  • Java代码:new一个需要的Drawable并set相关属性,最后加载到布局中。

Drawable可通过 getIntrinsicWidth() 和 getIntrinsicHeight() 获取其内部宽/高,并不是所有Drawable都有内部宽/高。
图片所形成的Drawable的内部宽/高就是图片的宽/高。
颜色所形成的Drawable没有内部宽/高的概念。
Drawable没有大小概念,使用范围单一:作为ImageView中的图像显示,作为View的背景

2.Drawable分类

2.1 BitmapDrawable

表示一张图片,可以直接引用原始的图片,也可以通过XML的方式描述

<?xml version-"1.0" encoding-"utf-8"?>
<bitmap
	xmIns: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"] />

android:src:图片资源的id
android:antialias:是否开启图片抗锯齿功能,一般开启,能让图片变得更平滑,清楚度降低
android:dither:是否开启抖动效果,当图片的像素配置和手机屏幕的像素配置不一致时,开启能够让高质量的图片在低质量的屏幕上保持比较好的显示效果,一般开启;android创建的Bitmap一般会选用ARGB8888色彩模式;
android:filter:是否开启过滤效果,当图片尺寸被拉伸或者压缩时,开启过滤效果可以保持较好的显示效果,一般开启。
android:titleMode:平铺模式,默认是disable关闭平铺模式,开启后gravity会被忽略;repeat表示的是简单的水平和竖直方向上的平铺效果;mirror表示一种在水平和竖直方向上的镜面投影效果;clamp表示图片四周的像素会扩展到周围区域。
在这里插入图片描述
1.XML定义

在Drawable文件夹中创建bg_tilemode_mirror.xml
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:dither="true"
    android:src="@mipmap/ic_launcher"
    android:tileMode="mirror"
    >
</bitmap>

在activity_main.xml中设置为View背景
<View
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg_tilemode_mirror"
    />

2.Java实现

//在MainActivity创建BitmapDrawable
		Bitmap bitmap =BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher);
        BitmapDrawable bitDrawable = new BitmapDrawable(bitmap);
        bitDrawable.setDither(true);
        bitDrawable.setTileModeXY(Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);

//加载到mylayout布局
        LinearLayout myLayout = (LinearLayout) findViewById(R.id.mylayout);
        myLayout.setBackgroundDrawable(bitDrawable);

借鉴学习:Bitmap使用指南

2.2 NinePatchDrawable

NinePatchDrawable 表示一张.9格式的图片,.9图片可以自动的根据所需要的宽高进行缩放,但是并不保证不失真,可以直接引用,也可以通过xml文件,< Bitmap >标签中可以使用.9格式的图片
属性:

<?xnl version-"1.0" encoding-"utf-8"?>
<nine-patch
	xmlng :android= "http: //schemas.android.com/apk/res/android"
	android:src= "@ [package: ]drawable/drawable_resource"
	android:dither=["true" | "false"] />

使用xml文件定义

//在Drawable文件夹中创建bg_nine_patch.xml
<?xml version="1.0" encoding="utf-8"?>
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
    android:dither="true"
    android:src="@drawable/ic_launcher"
    >
</nine-patch>

//在activity_main.xml中设置为EditText背景
<EditText
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg_nine_patch"
    />

2.3 ShapeDrawable

通过颜色来构造图形,可以是纯色的图形,也可以是具有渐变效果的图形
在这里插入图片描述

  • shape:定义形状的类型,默认情况下为rectangle(矩形),oval(椭圆)、line(横线)、ring(圆环),后两个选项必须通过标签来指定线的宽度和颜色等。
    仅当 android:shape=“ring” 时才使用以下属性:
    在这里插入图片描述
    仅当android:shape=’rectangle’ 才使用以下属性,对应标签< corners>:
    在这里插入图片描述
    其他属性:
<gradient>
指定形状的渐变颜色。他与<solid>标签是互斥的
属性:
android:angle
整型。渐变的角度()0为从左到右,90为从上到上。必须是45的倍数。默认值为0
android:centerx
浮点型。渐变中心的相对x轴位置(0 - 1.0)
android:centery
浮点型。渐变中心的相对Y轴位置(0 - 1.0)
android:centerColor
颜色。起始颜色与结束颜色之间的可选颜色,以十六进制值或颜色资源表示。
android:endColor
颜色。结束颜色,表示为十六进制值或颜色资源。
android: gradientRadius
浮点型。渐变的半径。仅在android:type="radial" 时适用。
android:startColor
颜色。起抬颜色,表示为十六进制值或颜色资源。
android:type
关键字。要应用的渐变图案的类型。
有效值为:
"linear" 线性渐变。这是默认值。
"radial" 径向渐变 。起始颜色为中心颜色。
"sweep"  流线型渐变。
android:useLevel  布尔值。如果这用作LevelListDrawabler 则此值为"true"<solid>
用于填充形状的纯色。
属性:
android:color  颜色。应用于形状的颜色,以十六进制值或颜色资源表示。

<stroke>
形状的笔划中线。
属性:
android:width  尺寸。线宽,以尺寸值或尺寸资源表示。描边的宽度,越大则shape的边缘就会越粗
android:color  颜色。线的颜色,表示为十六进制值或颜色资源。描边的颜色
android:dashGap  虚线的间距,以尺寸值或尺寸资源表示。仅在设置了android:dashidth 时有效
android:dashWidth   尺寸。每个虚线的大小,以尺寸值或尺寸资源表示。仅在设置了android:dashGap 时有效。
dashHidth与dashGap两个有任何一个为空 那么虚线就不生效

<padding>
这个表示空白,但是它表示的不是shape的空白,而是包含它的View的空白,有四个属性: android:left. android:top.android:right和android:bottom.

<size>
属性:
androld:height
尺寸。形状的高度,表示为尺寸值或尺寸资源
android:width
尺寸。形状的宽度,表示为尺寸值或尺寸资源
注:标签设置的宽高是ShapeDrawable的固有宽高,作为View背景的时候还会被拉伸或缩小为view的大小。
在ImageView 中使用形状时,可通过将android:scaleType 设置为"center" 来限制缩欣。

2.4 LayerDrawable

表示一种层次化Drawable集合,通过将不同的Drawable放置在不同的层上面从而达到叠加后的效果

<?xml version-"1.0" encoding-"utf-8"?>
<layer-list
	xmlns:androld-"http://schemas.androld.com/apk/res/android" >
	<item
		android:drawable-"@ [package: ] drawable/drawable_resource"
		android:id="@[+] [package:] id/resource_name"
		android:top= "dimension"
		android:right= "dimension"
		android:bottom= "dimension"
		android:left- "dimension" />
</layer-list>

一个 layer-list 中可以包含多个item,每个item表示一个Drawable. Item 常用的属性有android:top. android:bottom. android:left 和android:right,它们分别表示Drawable 相对于View的上下左右的偏移量,单位为像素。另外,可以通过android:drawable属性来直接引用一个已有的Drawable 资源,也可以在item 中自定义Drawable。默认情况下,layer-list 中的所有的Drawable都会被缩放至View的大小,对于bitmap来说,需要使用android:gravity属性才能控制图片的显示效果。Layer-list 有层次的概念,下面的item会覆盖上面的item,通过合理的分层,可以实现一些特殊的叠加效果。

2.5 StateListDrawable

对应标签,表示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-l"true" | "false" ]
		android:dither- ["true"| "false"]
		android:variablePadding=["true" | "false"] >
	<item
	androld:drawable="@ [package: Idrawable/drawable_ resource"
	android:state_pressed= ["true" | "false"]
	android:state_focused= ["true"| "false"]
	androld:state_ hovered=["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:constantSize
StateListDrawable的固有大小是否不随着其状态的改变而改变的,因为状态的改变会导致StateListDrawable切换到具体的Drawable,而不同的Drawable具有不同的固有大小。True表示StateListDrawable的固有大小保持不变,这时它的固有大小是内部所有Drawable的固有大小的最大值,false 则会随着状态的改变而改变。此选项默认值为false.
android:dither
是否开启抖动效果,这个在BitmapDrawable中也有提到,开启此选项可以让图片在低质量的屏幕上仍然获得较好的显示效果。此选项默认值为true.
android:variablePadding
StateListDrawable的padding表示是否随着其状态的改变而改变,true 表示会随着状态的改变而改变,false 表示StateListDrawable 的padding是内部所有Drawable的padding的最大值。此选项默认值为false,并且不建议开启此选项。
在这里插入图片描述
在这里插入图片描述

2.6 LevelListDrawable

LevelListDrawable对应于< level-list>标签,它同样表示一个 Drawable集合,集合中的每个Drawable都有一个等级(level) 的概念。根据不同的等级,LevelL istDrawable会切换为对应的Drawable

<?xml version-"1. 0" encoding="utf-8"?>
	<level-list  xmIns:android= "http:// schemas.android.com/apk/res/android" >
	<item
	android : drawable="@drawable/drawable resource 
	android : maxLevel="integer"
	android : minLevel="integer" />
</level-list>

每个item表示一个Drawable,并且有对应的等级范围,由android:minLevel和android:maxLevel 来指定,在最小值和最大值之间的等级会对应此item中的Drawable.当它作为View的背景时可以通过Drawable 的setLevel方法来设置不同的等级从而切换具体的Drawable. 如果它被用来作为ImageView 的前景Drawable,那么还可以通过ImageView 的setlmageLevel 万法来切换Drawable.Drawable的等级是有范围的,即0~10000,最小等级是0,这也是默认值,最大等级是10000.加载规则:当某item的android:maxLevel 等于 setLevel所设置的数值时就会被加载。若都没有匹配的则都不显示

2.7 TransitionDrawable

LayerDrawable的子类,实现两层 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:top= "dimension"
		android:right= "dimension"
		android:bottom= "dimension"
		android:left="dimension" />
</transition>

使用过程:
无论是用xml还是代码实现,若作为View背景,都需要在Java代码中调用startTransition()方法才能启动两层间的切换动画,也可以调用reverseTransition()方法反方向切换。
1.首先定义TransitionDrawable
2.然后设置view的background或直接作为Drawable
3.最后通过它的startTransition和reverse Transition方法来实现淡入淡出的效果以及它的逆过程,如下所示。

在Drawable文件夹中创建bg_tran.xml
<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/image1"/>
    <item android:drawable="@drawable/image2"/>
</transition>

在activity_main.xml中设置为ImageView背景
 <ImageView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/bg_tran"/>

在MainActivity调用startTransition()
        ImageView imageView = (ImageView) findViewById(R.id.image);
        TransitionDrawable td = (TransitionDrawable) imageView.getDrawable();
        td.startTransition(3000);

2.8 InsetDrawable

表示把一个Drawable嵌入到另外一个Drawable的内部,并在四周留一些间距。与Drawable的padding属性不同:padding表示的是Drawable的内容与Drawable本身的边距;而InsetDrawable表示的是两个Drawable与容器之间的边距。适用于当空间需要的背景比实际的边框小的时候。
属性:

inset
    |- drawable="@drawable/drawable_id"
    |- visible="[true | false]"   是否留有边距
    |- insetTop="dimension"       设置距离外容器的上边距
    |- insetLeft="dimension"
    |- insetRight="dimension"
    |- insetBottom="dimension"

实例:

//在drawable文件夹下创建
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/image"
    android:insetBottom="40dp"
    android:insetLeft="10dp"
    android:insetRight="30dp"
    android:insetTop="20dp"
    android:visible="true">
</inset>

2.9 ScaleDrawable

对应于< scale>标签,它可以根据自己的等级(level)将指定的Drawable,缩放到一定比例

scale
    |- drawable="@drawable/drawable_id"
    |- scaleGravity="[top | bottom | left | right |
        center_vertical | center_horizontal | center |
        fill_vertical | fill_horizontal | fill |
        clip_vertical | clip_horizontal]"
    |- scaleWidth="percentage"
    |- scaleHeight="percentage"  
     指定Drawable宽/高的缩放比例,以百分比的形式表示。

使用方法:
无论是用xml还是代码实现,若作为View背景,都需要在Java代码中调用setLevel()方法控制Drawable等级。ScaleDrawable的等级和内部的子Drawable的等级是保持一致的
level取值范围为0~ 10000。 默认值为0:表示不可见;1~10000:表示可见
如果ScaleDrawable的级别为最大值10000,那么就没有缩放的效果;如果ScaleDrawable的级别(level) 越大,那么内部的Drawable看起来就越大:如果ScaleDrawable的XML中所定义的缩放比例越大,那么内部的Drawable
看起来就越小。

//在drawable文件夹下创建bg_scale.xml
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/drawable_test"
    android:scaleGravity="center"
    android:scaleHeight="70%"
    android:scaleWidth="70%"/>

//在activity_main.xml中设置为ImageView背景
 <ImageView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/bg_scale"/>

//在MainActivity调用setLevel()
         ImageView imageView = (ImageView) findViewById(R.id.image);
        ScaleDrawable scaleDrawable = (ScaleDrawable) imageView.getDrawable();
        scaleDrawable.setLevel(1);

2.10 ClipDrawable

ClipDrawable对应于标签,它可以根据自己当前的等级(level) 来裁剪另一个Drawable,裁剪方向可以通过android:clipOrientation和android:gravity这两个属性来共同控制

scale
    |- drawable="@drawable/drawable_id"
    |- gravity="[top | bottom | left | right |
        center_vertical | center_horizontal | center |
        fill_vertical | fill_horizontal | fill |
        clip_vertical | clip_horizontal]"
    |- clipOrientation="[vertical | horizontal]"

其中clipOrientation 表示裁剪方向,有水平和竖直两个方向,gravity 比较复杂,需要和clipOrientation 一起才能发挥作用
在这里插入图片描述
使用方法:

  1. 自定义一个ClipDrawable的xml文件
  2. 将xml设置给ImageView
  3. 在代码中设置ClipDrawable的等级
ImageView testClip = (ImageView) findViewById(R.id.test_ clip);
ClipDrawable testClipDrawable = (ClipDrawable) testClip.getDrawable();
testClipDrawable.setLevel(8000) ;

等级(level)是有范围的,即0~10000,最小等级是0,最大等级是10000,对于ClipDrawable 来说,等级0表示完全裁剪,即整个Drawable都不可见了,而等级10000 表示不裁剪。在上面的代码中将等级设置为8000 表示裁剪了2000,即在顶部裁剪掉20%的区域,被裁剪的区域就相当于不存在了

3.自定义Drawable

  • Drawable的工作原理的核心是draw():系统调用Drawable的draw()来绘制View的背景或ImageView的图像。
  • 通常没有必要去自定义Drawable,因为无法在XML中使用自定义Drawable,这就降低了其使用范围。
  • 创建自定义Drawable,必须重写其draw()、setAlpha()、setColorFilter()、getOpacity()等方法。
  • 当自定义的Drawable有固有大小时,最好重写getIntrinsicWidth()getIntrinsicHeight(),因为它会影响到View的wrap_content布局。
  • Drawable的内部大小不等于Drawable的实际大小,后者可通过getBounds()获得,一般它和View的尺寸相同。

借鉴:Drawable完全解析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值