Drawable的基础用法

1、前言

今天来跟大家聊一聊关于Android当中的绘图技巧,绘图技巧,不管是自定义控件,还是在我们去做自定义商业动画,都会常常的使用到,所以在这里和大家聊一聊关于绘图技巧的问题,如果那里有错误,希望各位大神指出。

2、正文

我们知道绘图的话,关于画布,画笔,这些Goolge提供的类有很大的关联,但是我们今天着重不是这些,而是从我们要给什么地方画图,这个是今天的重点,至于画图的细节我们以后会说的。

Android系统当中把我们所有的关于可以绘制的对象抽象出来,叫做Drawable对象,相信这个对象大家一定都不会陌生,在我们的实际开发当中我们基本天天都能遇到,今天就和大家聊一聊关于Drawable的各种用法。

我们想一想在我们的实际开发当中我们是怎么样去运用我们的Drawable的,我们会在res/drawable这个资源文件下面定义各种各样的Xml的文件,我们的Xml有不同的节点,其实我们这里的一个Xml的节点,就对应我们的Drawable的实现类,也就是说我们我们创建出来的Xml的文件,会被SDK自动的根据你的节点去创建相应的一个Drawable实现来,从而去实现我们所要的效果,在这里我们可以去类比一下我们的View,我们View当中的控件貌似也是这么定义的,在Xml当中去设定我们View控件所要的属性。但是我们的View可以在代码当中New出来,我们在这里试想一下,我们的Drawable也是可以在代码当中去new出来的,然后通过代码去给他去添加属性,答案是可以的,但是我们又想了想,我们new一个View有用么,我们一般不是new一个Button,一个ImageVeiw的么,我们可以去new一个Drawable的实现类,然后通过Drawable去进行管理,就像我们可以去用我们的View,ViewGroup去管理我们的控件和布局。

那么我们来看看Drawable的哪些节点对应的哪些实现类呢!然后会给大家详细的去做介绍。为了让各位看的更加的清楚,相信大家就非常的清楚了

  • selector : StateListDrawable
  • layer-list : LayerDrawable
  • transition : TransitionDrawable
  • color : ColorDrawable
  • shape : GradientDrawable
  • scale : ScaleDrawable
  • clip : ClipDrawable
  • rotate : RotateDrawable
  • animation-list : AnimationDrawable:
  • insert : InsetDrawable:
  • bitmap : BitmapDrawable
  • nine-patch : NinePatchDrawable:

1 selector StateListDrawable

这个叫做状态的选择器,首先我们需要明白一点,就是StateListDrawable里面维护了不止一个Drawable对象,就是一组Drawable对象。既然它叫做状态选择器,说白了就是可以去根据不同的状态去返回不同的Drawable对象,而这些状态是由系统去进行提供的,至于都有哪些状态,按下状态、选中状态、默认状态、禁用状态等等,如果想了解更加全面,请大家参考Google的API,我们的Button的背景一般都使用这个Drawable,还有就是TV的海报也是用它,基本我们去和用户做交互的控件的背景都会使用到它

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<selector xmlns:android="http://schemas.android.com/apk/res/android">

<!-- state_pressed:代表用户按下状态 -->
<item android:state_pressed="true" android:drawable="@drawable/press"/>

<!-- 如果状态什么都不写,代表默认状态,就是什么都不触发的时候 -->
<item android:drawable="@drawable/normal"/>

<!-- 没有焦点时的背景图片 -->
<!--<item android:state_window_focused="false" android:drawable="@drawable/pic1" />-->
<!-- 非触摸模式下获得焦点并单击时的背景图片 -->
<!--<item android:state_focused="true" android:state_pressed="true" android:drawable= "@drawable/pic2" />-->
<!-- 触摸模式下单击时的背景图片-->
<!--<item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/pic3" />-->
<!--选中时的图片背景-->
<!--<item android:state_selected="true" android:drawable="@drawable/pic4" />-->
<!--获得焦点时的图片背景-->
<!--<item android:state_focused="true" android:drawable="@drawable/pic5" />-->
<!--设置是否响应事件,指所有事件-->
<!--<item android:android:state_enabled="true" android:drawable="@drawable/pic5" />-->

</selector>

在我们的Layout当中只需要引入一下我们刚刚用Xml定义的Drawable,就OK了

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/selector_bg" />

</RelativeLayout>

效果图如下,当我点击的按下的时候会发生改变,当我抬起的时候会变为原来的,这只是一种状态,还有别的状态,笔者这里就不一一列举了

StateListDrawable

2、level-list LevelListDrawable

这个我的理解是自定义选择器,首先在LevelListDrawable里面和我们StateListDrawable一样,维护了一组的Drawable的对象,同时维护了每一个Drawable要显示的Level范围,不同的是上述是通过系统发出的状态去做出一个处理去显示我们的Drawable对象,而这个是自己定义一个范围去匹配响应的Drawable去显示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<level-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:drawable="@drawable/fm_vehicle_linking_1"
android:maxLevel="1"/>
<item
android:drawable="@drawable/fm_vehicle_linking_2"
android:maxLevel="2"/>
<item
android:drawable="@drawable/fm_vehicle_linking_3"
android:maxLevel="3"/>
<item
android:drawable="@drawable/fm_vehicle_linking_4"
android:maxLevel="4"/>
<item
android:drawable="@drawable/fm_vehicle_linking_5"
android:maxLevel="5"/>
<item
android:drawable="@drawable/fm_vehicle_linking_6"
android:maxLevel="6"/>
<item
android:drawable="@drawable/fm_vehicle_linking_7"
android:maxLevel="7"/>
<item
android:drawable="@drawable/fm_vehicle_linking_8"
android:maxLevel="8"/>
<item
android:drawable="@drawable/fm_vehicle_linking_9"
android:maxLevel="9"/>
<item
android:drawable="@drawable/fm_vehicle_linking_10"
android:maxLevel="10"/>
<item
android:drawable="@drawable/fm_vehicle_linking_11"
android:maxLevel="11"/>
<item
android:drawable="@drawable/fm_vehicle_linking_12"
android:maxLevel="12"/>
<item
android:drawable="@drawable/fm_vehicle_linking_13"
android:maxLevel="13"/>
<item
android:drawable="@drawable/fm_vehicle_linking_14"
android:maxLevel="14"/>
</level-list>

我们的Layout使用一个seekBar 和一个ImageView去展示我们的图片,相当于一个载体。没有什么难度,楼主在这里就不去贴图片了我们直接来看看我们的Activity的代码,在我们的seekBar上面增加一个监听器,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/** 初始化View */
private void initView() {
final ImageView image = (ImageView) findViewById(R.id.iv);
final Drawable drawable = getResources().getDrawable(R.drawable.levellist);
SeekBar seekBar = (SeekBar) findViewById(R.id.seekBar);
seekBar.setMax(14);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
drawable.setLevel(progress);
image.setImageDrawable(drawable);
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}

@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}

效果呢!就是如下这样啦

LevelListDrawable

3、layer-list LayerDrawable

这个是图层的Drawable,它同样是维护了一组的Drawable,但是会根据我们在XML当中定义的顺序去给它做一个顺序显示,列表的最后一个drawable绘制在最上层。每一个Drawable处于一个不同的图层,也许会出现重叠,交叉的现象,但是不会首到另外Drawable的影响。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

<item android:drawable="@drawable/live_color_2"/>

<!-- android:top - Integer。与top的距离,单位像素
android:right - Integer。与right的距离,单位像素
android:bottom - Integer。与bottom的距离,单位像素
android:left - Integer。与left的距离,单位像素
-->

<!--
在默认的情况下,所有的drawable item都会缩放到合适的大小来适应视图。
因此,在一个layer-list中定义不同的位置可能会增加视图的尺寸和被自动缩放。
为了避免被缩放,可以再<item>节点里加上<bitmap>元素来指定一个drawable,
并且定义一些不会被拉伸的gravity属性,例如center。

<item>
<bitmap android:src="@drawable/image"
android:gravity="center" />
</item>

-->
<item android:drawable="@drawable/live_color_3"
android:top="30dip"
android:left="30dip"
android:right="30dip"
android:bottom="30dip"
/>

<item android:drawable="@drawable/live_color_4"
android:top="60dip"
android:left="60dip"
android:right="60dip"
android:bottom="60dip"
/>

</layer-list>

我们的Layout同第一个一样,直接去引用一下就OK

1
2
3
4
5
6
7
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/layerlist"
/>

效果呢,如下,但是请注意上述注释里面所说的情况

LayerDrawable

4、transition TransitionDrawable

这是一个LayerDrawable子类,那么它涉及到的也将会是图层的知识,但是他只涉及到了两个图层的变化,就是把上面和下面的图层进行交替显示,通过改变他们的透明度,为维护了一个平滑的透明度变化的动画效果,开启动画调用startTransition()。可以反向开启调用 reverseTransition()。

1
2
3
4
5
6
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 一个青色的小圆 -->
<item android:drawable="@drawable/live_color_2"/>
<!-- 一个黄色的小圆 -->
 <item android:drawable="@drawable/live_color_4"/>
</transition>

Activity里面去设置一下这个Drawable,比如什么时候开启过度透明度动画,设置动画时长之类的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView image = (ImageView) findViewById(R.id.iv);

Resources res = getResources();
TransitionDrawable transition = (TransitionDrawable)res.getDrawable(R.drawable.transition);

image.setImageDrawable(transition);
transition.startTransition(2000);
// 这个是反向开启动画
// transition.reverseTransition(2000);
}

效果如下:

TransitionDrawable

5、color ColorDrawable

这个Drawable对象,描述的不像上面的,它描述一个单个Drawable,在其内部定义颜色属性,当要绘制的时候,会读取到里面的颜色值,把这个颜色设置给将要绘制的Paint对象上面,注意这个Drawable一旦绘制,就不好修改了。

1
2
3
<?xml version="1.0" encoding="utf-8"?>
<color xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#FF0000"/>

颜色是怎么归类的 6位 ARGB 这个楼主就默认大家都会了,也就不浪费时间了

6、shape GradientDrawable

这个Drawable大家可以理解为上述ColorDrawable的加强版,在这个Drawable中维护了很多属性,好方便我们来使用,使用这个Drawable,我们可以实现是一个区域内的颜色渐变,其中主要分为线性渐变,发散渐变,平铺渐变,下面我们来研究一下,在它的内部定义了什么属性来达到我们实现炫酷的效果

  • 1、size:定义区域的大小
  • 2、gradient:设置区域背景的渐变效果
  • 3、solid:设置区域的背景颜色,如果设置了solid会覆盖gradient的效果
  • 4、stroke:设置区域的边框效果
  • 5、padding:设置区域的内边距,

这个Drawable很常用,同时也很重要,所以楼主会详细一点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<?xml version="1.0" encoding="utf-8"?>
<!--
rectangle 长方形 /默认
oval 椭圆
line 线
ring 环形
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">

<!-- 用来描述渐变的类型,线性渐变,发散渐变,平铺渐变,还有渐变开始颜色,渐变结束颜色 -->
<!--
angle 是颜色变换的角度, 默认是0, 取值必须是45的 倍数. 0: 是颜色从左边到右边, 90: 是颜色从底部到顶部,
startColor centerColor endColor 一起使用: 开始的颜色, 中间的颜色, 结束的颜色
centerX centerY是指定位置坐标, 取值是0.0f ~ 1.0f 之间, 例如: android:centerX="0.5f" 表示X方向的中间位置
gradientRadius 和android:type="radial"一起连用,

android:type:
radial 平铺渐变, 例如: 从一个圆中心到圆的边缘变化
sweep 发散渐变, 类似雷达扫描的那种图形
linear 线性渐变, 就是颜色从左往右, 从下往上
-->
<gradient
android:startColor="#FF0000"
android:centerColor="#00FF00"
android:endColor="#0000FF"
android:type="linear"/>


<!-- 用来定义显示区域的大小 -->
<!--
这里一般不用设置, 它的优先级没有控件的优先级大,
他指定控件的宽高就好, shape图形会随控件拉伸
-->
<!--
<size
android:width="100dp"
android:height="100dp"
/>
-->

<!-- 用来定义圆角 -->
<!--
bottomLeftRadius 左下角
bottomRightRadius 右下角
topLeftRadius 左上角
topRightRadius 右上角

radius 是四个角, 设置了这个就不需要设置上面的四个了, PS:它的优先级比较低, 会被其他参数覆盖
-->
<corners
android:bottomLeftRadius="10dp"
android:bottomRightRadius="10dp"
android:topLeftRadius="10dp"
android:topRightRadius="10dp"/>

<!-- padding标签: 这里的padding是控件中间内容与shape图形图片的距离 -->
<padding
android:bottom="5dip"
android:left="5dip"
android:right="5dip"
android:top="15dip"/>

<!--solid标签: shape图形背景色, 这个和上面的gradient标签会互斥, 一个是设置背景色, 一个是设置渐变色, 上述也说过这个问题 -->
<!--
<solid
android:color="@android:color/white"/>
-->

<!-- 边框的颜色宽度的设置 -->
<!--
width 边框的宽度
color 边框的颜色

边框的样式:
dashGap 虚线中空格的长度
dashWidth 虚线中实线的长度
-->

<stroke
android:width="5dip"
android:color="#0000FF"
android:dashGap="2dip"
android:dashWidth="1dip"/>

</shape>

效果如下:

GradientDrawable

7、scale ScaleDrawable

这个Drawable主要就是对原有的Drawable去进行一定百分比的缩放,我们可以选取不同的缩放中心对这个Drawable进行控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>

<!--
drawable Drawable 资源。必须的。引用一个drawable资源。
scaleHeight 缩放的高度,以百分比的方式表示drawable的缩放。形式例如:100%,12.5%。
scaleWidth 缩放的宽度,以百分比的方式表示drawable的缩放。形式例如:100%,12.5%。
scaleGravity 指定缩放后的gravity的位置。必须是下面的一个或多个值(多个值之间用”|”分隔)
-->

<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/press"
android:scaleGravity="center_vertical|center_horizontal"
android:scaleHeight="50%"
android:scaleWidth="50%" />

准备好以后,我们来运行一下,但是我们发现并没有显示图片,查看ScaleDrawable的源码,发现draw()方法有判断getLevel() != 0才绘制。而我们在没有setLevel()时,默认getLevel()都是0。
那我们先设置10000吧,我们再次运行,发现没有按照我们50%的比例进行缩放,然后我们去看官方文档

  • A Drawable that changes the size of another Drawable based on its current level value,

我们发现ScaleDrawable的缩放,并不是自动的建立在原有Drawable尺寸的基础上的。而是,需要给原有的Drawable指定一个Level,然后ScaleDrawable是在这个Level的基础上进行缩放的!
注意:设置的值是缩小的比例。也就是说,设置0.5,意为缩小50%!!而不是原始大小的50%
那么我们在我们的Activity里面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

ScaleDrawable drawable = (ScaleDrawable) getResources().getDrawable(R.drawable.scale);

ImageView image = (ImageView) findViewById(R.id.iv);
image.setImageDrawable(drawable);
//在这个地方设置Level
 image.setImageLevel(1);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

ScaleDrawable drawable = (ScaleDrawable) getResources().getDrawable(R.drawable.scale);

ImageView image = (ImageView) findViewById(R.id.iv);
image.setImageDrawable(drawable);
//在这个地方设置Level
 image.setImageLevel(1);
}

效果呢 如下:

ScaleDrawable

8、clip ClipDrawable

这个Drawable主要就是对原有的Drawable进行一个裁剪,我们会有gravity选择在父容器的对齐方式,然后通过Drawable提供的level去设置我们去裁剪的大小,裁剪是从0到10000,0代表完全不显示,10000代表完全显示。

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8"?>
<!--
drawable:所需要的Drawable资源
clipOrientation:裁剪的方向,垂直,水平
gravity:对齐方式
-->
<clip xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/press"
android:clipOrientation="horizontal"
android:gravity="center"/>

定义出了我们自已要的Drawable,然后在我们的Activity进行应用就OK了

下面看Activity的代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}

/** 初始化View */
private void initView() {
final ImageView image = (ImageView) findViewById(R.id.iv);
final ClipDrawable drawable = (ClipDrawable) getResources().getDrawable(R.drawable.clip);
SeekBar seekBar = (SeekBar) findViewById(R.id.seekBar);
seekBar.setMax(10000);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
drawable.setLevel(progress);
image.setImageDrawable(drawable);
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}

@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}

下面贴出效果图

ClipDrawable

9、rotate RotateDrawable

这个Drawable主要就是对原有的Drawable进行一定角度的旋转,基于当前的level,进行旋转的drawable。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<!--drawable: Drawable 资源。必须的。引用一个drawable资源。
visible:Boolean。是否可见。
fromDegrees:整形。 从多少的角度开始旋转
toDegrees:整形。 到多少的角度结束旋转
pivotX:百分比。 旋转的中心在图片X轴的百分比
pivotY:百分比。 旋转的中心在图片Y轴的百分比-->

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/press"
android:visible="true"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%">
</rotate>

在这里我们对旋转度数做一个详细的介绍,

图片将从0到360进行旋转。level值为10000,也就是说level每加1000,即顺时针旋转360/10000*1000=36度。
可以根据显示看出来效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}

/** 初始化View */
private void initView() {
final ImageView image = (ImageView) findViewById(R.id.iv);
final RotateDrawable drawable = (RotateDrawable) getResources().getDrawable(R.drawable.rotate);
SeekBar seekBar = (SeekBar) findViewById(R.id.seekBar);
seekBar.setMax(10000);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
drawable.setLevel(progress);
image.setImageDrawable(drawable);
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}

@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}

效果呢,如下:

RotateDrawable

10、animation-list AnimationDrawable

这个Drawable里面维护了一组Drawable,通过一定的顺序,一定的显示时长去做一个Drawable的逐个显示,那么这么就会形成一个动画,也就是说每一个Drawable就是这个动画当中的一个帧,你可以通过oneshot属性来控制该动画播放完毕以后是否重新播放,主动调用AnimationDrawable的start播放动画,关于AnimationDrawable这个动画大家可以去看一下我的关于动画专题的博客。

11、inset InsetDrawable

这个Drawable主要是说可以把一个Drawable插入到另外一个Drawable的内部,并且在内部留一些间距

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--
drawable: Drawable 资源。必须的。引用一个drawable资源。
insetBottom:整形。 底边距的大小
insetLeft:整形。 左边距的大小
insetRight:整形。 右边距的大小
insetTop:整形。 上边距的大小
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/press"
android:insetBottom="30dp"
android:insetLeft="30dp"
android:insetRight="30dp"
android:insetTop="30dp" >
</inset>

layout:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:gravity="center">

<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="#aaa"
android:src="@drawable/insert"
/>
</RelativeLayout>

效果如下

InsetDrawable

12、bitmap BitmapDrawable

这个Drawable主要是对Bitmap的一种封装,可以设置它包装的bitmap在BitmapDrawable区域内的绘制方式,如平铺填充、拉伸填充或者保持图片原始大小,也可以在BitmapDrawable区域内部使用gravity指定的对齐方式。
BitmapDrawable就是封装了一个位图。以文件的方式,封装一个原始的位图。以Xml方式,可以对原始的位图进行一系列的处理,比如说抗锯齿,拉伸,对齐等等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="utf-8"?>
<!--

src(Drawable) resource:必需。 引用一个drawableResource.
antialias (Boolean): 是否开启抗锯齿。
dither (Boolean): 如果位图与屏幕的像素配置不同时,是否允许抖动.(例如:一个位图的像素设置是 ARGB 8888,但屏幕的设置是RGB 565)
filter (Boolean): 是否允许对位图进行滤波。对位图进行收缩或者延展使用滤波可以获得平滑的外观效果。
gravity: 定义位图的重力(gravity),如果位图小于其容器,使用重力指明在何处绘制
tileMode:
"disabled" :默认值,什么也没有
"clamp" :复制图片边缘的颜色来填充容器剩下的空白部分,比如引入的图片如果是白色的边缘,那么图片所在的容器里除了图片,剩下的空间都会被填充成白色
"repeat" :平铺
"mirror":镜面
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:alpha="1"
android:antialias="true"
android:dither="true"
android:filter="true"
android:gravity="clip_vertical"
android:src="@drawable/press"
android:tileMode="disabled"
/>

layout:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
>

<ImageView
android:id="@+id/iv"
android:layout_width="400dip"
android:layout_height="400dip"
android:src="@drawable/bitmap"
/>

</RelativeLayout>

效果:

BitmapDrawable

13、nine-patch

NinePatchDrawable:这个就是我们知道的点九图片,也就是.9.png,会根据内容的大小对其内容进行拉伸,注意:但是不能压缩,这也就是我们看到的切图为什么一开始都会做得很小,

1
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/list_tag_clear"
android:dither="true"/>

我们要明白src对应的应该是一个.9图片,
dither 是否图像抖动处理,当每个颜色值以低于8位表示时,对应图像做抖动处理可以实现在可显示颜色总数比较低(比如256色)时还保持较好的显示效果。

layout:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
>

<Button
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="assssssssssssssssssssssssssssssssssssssssss"
android:background="@drawable/nine" />

</RelativeLayout>

注意:有可能会出Error:java.lang.RuntimeException: Some file crunching failed, see logs for details

意思就是说

  • 1.构建Gradle的时候,Gradle会去检查一下是否修改过文件的后缀名;
  • 2.一般大多数是出现在图片上,.jpg修改成了.png就会出现这个问题;
  • 3.9patch图片也可能出现这个问题。

很明显我们可能是第三种情况