在Android层次结构中,资源扮演着非常重要的角色。在Android中,资源是绑定到可执行程序的文件或值。这些文件和值绑定到可执行程序的方式很友好,无需重新编译和重新部署应用程序就能更改他们。熟悉的资源包括:字符串,颜色和位图等
Android应用下除了res目录用于存放资源文件之外,assets目录也用于存放资源,一般来说,assets目录下存放的资源代表应用无法直接访问的原生资源,应用程序需要通过AssetManager以二进制流的形式来读取资源。而res目录下的资源,Android SDK会在编译该应用时,自动在R.java文件中为这些资源创建索引,程序可直接通过R资源清单类进行访问。
1. 资源的类型及存储方式
Android应用资源可分为两大类:
- 无法通过R清单访问的原生资源,保存在assets目录下
- 可通过R资源清单类访问的资源,保存在res目录下
1.1 资源的类型以及存储方式
Android要求在res目录下用不同的子目录来保存不同的应用资源,res下常用的目录如下:
- /res/animator/: 存放定义属性动画的xml文件
- /res/anim/: 存放定义补间动画的xml文件
- /res/layout/: 存放布局文件
- /res/menu/: 存放各种菜单资源,包括选项菜单,子菜单,上下文菜单
/res/drawable/: 该目录下存放各种位图文件(如*.png, *.9.png, *.jpg, *.gif)等。除此之外也可是能编译成如下各种Drawable对象的xml文件:
- BitmapDrawable
- NiniPatchDrawable对象
- StateListDrawable对象
- ShapeDrawable对象
- AnimationDrawable对象
- Drawable的其他各种子类的对象
/res/raw/: 该目录下存放任意类型的原声资源(比如音频文件,视频文件等)。在Java代码中可通过调用Resources对象的openRawResource(int id)方法来获取该资源的二进制输入流。实际上,如果应用程序需要使用原声资源,推荐把这些原生资源保存到/assets目录下,然后在应用程序中使用AssetManager来访问这些资源
- /res/values/: 存放各种简单值的xml文件(比如:字符串值,整数值,颜色,尺寸,数组等),而且这些资源文件的根元素都是
<resources.../>
元素
- string/integer/bool子元素:代表添加一个字符串值,整数值或boolean值
- color 子元素:代表添加一个颜色值
- array 子元素或string-array、int-array 子元素:代表添加一个数组
- style 子元素:代表添加一个样式
- dimen 子元素:代表添加一个尺寸
为了减少维护难度,建议将不同类型的资源存放在不同的文件中,例如: - arrays.xml: 定义数组资源
- colors.xml: 定义颜色资源
- dimens.xml: 尺寸资源
- strings.xml: 定义字符串资源
- styles.xml: 定义样式资源
- /res/xml: 任意的原生xml文件
1.2 使用资源
在Java代码中访问实际资源
在xml代码中使用资源
2. 使用字符串、颜色、尺寸、整数、布尔资源
字符串资源,颜色资源,尺寸资源,整数资源,布尔资源,他们对应的xml文件都位于/res/values目录下,他们默认的文件名,以及在R类中对应的内部类如下图所示:
资源类型 | 资源文件默认名 | 对应于R类中的内部类的名称 |
---|---|---|
字符串资源 | /res/values/strings.xml | R.string |
颜色资源 | /res/values/colors.xml | R.color |
尺寸资源 | /res/values/dimens.xml | R.dimen |
整数资源 | 无 | R.integer |
布尔资源 | 无 | R.bool |
2.1 字符串、颜色、尺寸、整数、布尔资源的定义
字符串资源:/res/values/strings.xml
<resources> <string name="app_name">DrawableDemo</string> <string name="hello">Hello World, XmlResTest!</string> <string name="parse">解析XML资源</string> <string name="style1">样式1的格式</string> <string name="style2">样式2的格式</string> </resources>
颜色资源:/res/values/colors.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#3F51B5</color> <color name="colorPrimaryDark">#303F9F</color> <color name="colorAccent">#FF4081</color> </resources>
尺寸资源:/res/values/dimens.xml
<resources> <dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen> </resources>
整数资源:/res/values/integers.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <integer name="Cat">20</integer> <integer name="Dog">30</integer> </resources>
布尔资源:/res/values/bools.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <bool name="is_male">true</bool> <bool name="is_big">false</bool> </resources>
2.2 字符串、颜色、尺寸、整数、布尔资源的使用
xml代码中使用
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/colorPrimary" android:text="New Button" android:id="@+id/button"/>
Java代码中使用
Resources res = getResources(); int color = res.getColor(R.color.colorPrimaryDark); button.setTextColor(color);
3. 数组资源
Android并为默认提供数组资源文件,一般来说我们采用位于/res/values目录下的arrays.xml文件来定义数组,定义数组时xml资源文件的根元素也是<resources.../>
,该元素内可包含如下三种子元素数组:
<array.../>
子元素:定义普通类型的数组,例如Drawable数组<string-array.../>
子元素:字符串数组<integer-array.../>
子元素:整数数组
3.1 数组资源的定义
…/res/values/arrays.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 定义一个Drawable数组 -->
<array name="plain_arr">
<item>@color/c1</item>
<item>@color/c2</item>
<item>@color/c3</item>
</array>
<!-- 定义字符串数组 -->
<string-array name="string_arr">
<item>@string/c1</item>
<item>@string/c2</item>
<item>@string/c3</item>
</string-array>
<!-- 定义整数数组 -->
<integer-array name="integer_attr">
<item>1</item>
<item>2</item>
<item>3</item>
</integer-array>
</resources>
3.2 数组资源的使用
xml使用
<ListView android:layout_width="match_parent" android:layout_height="wrap_content" android:entries="@array/string_arr">
Java代码使用
为了能在Java程序访问到实际数组,Resources提供了如下方法:
- getStringArray:获取字符串数组
- getIntArray:获取整数数组
- TypedArray obtainTypedArray(int id):根据资源文件中普通数组资源的名称来获取实际的普通数组
// 获取系统定义的数组资源 String[] texts; Resources res = getResources(); texts = res.getStringArray(R.array.string_arr); TypedArray icons = res.obtainTypedArray(R.array.plain_arr); // 使用颜色资源来设置文本框的背景色 text.setBackgroundDrawable(icons.getDrawable(position));
4. 使用Drawable资源
在Android中,不仅可以直接使用*.png, *.9.png, *.jpg, *.gif等图片作为Drawable资源,也可使用多种XML文件作为资源,只要一份XML文件可以被系统编译成Drawable子类的对象,那么这份XML文件即可作为Drawable资源
Drawable资源通常保存在/res/drawable-xxx 目录,目前又新增了一个/res/mipmap-xxx目录,这个目录和drawable目前没什么区别,把他当成原先的drawable目录就可以了
4.1 图片资源
最简单的Drawable资源,只要把*.png, *.9.png, *.jpg, *.gif等格式的图片放入/res/drawable-xxx或/res/mipmap-xxx等目录下,Android SDK就会在编译应用中自动加载图片,并在R资源清单类中生成该资源的索引。
文件名(包括路径) | XML访问语法格式 | JAVA访问语法格式 |
---|---|---|
/res/drawable/a.jpg | @drawable/a | R.drawable.a |
/res/drawable-hdpi/a.jpg | @drawable/a | R.drawable.a |
/res/mipmap/a.jpg | @mipmap/a | R.mipmp.a |
/res/mipmap-mdpi/a.jpg | @mipmap/a | R.mipmp.a |
4.2 StateListDrawable资源
StateListDrawable 用于组织多个Drawable对象。当使用StateListDrawable作为目标组件的背景、前景图片时,StateListDrawable对象所显示的Drawable对象会随目标组件的状态的改变而改变
它的使用方法如下:
定义StateListDrawable对象所对银的XML文件
res/drawable/my_stateListDrawable.xml
<?xml version="1.0" encoding="UTF-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 指定获得焦点时的颜色 --> <item android:color="#f44" android:state_focused="true"/> <!-- 指定失去焦点时的颜色 --> <item android:color="#eee" android:state_focused="false"/> </selector>
引用StateListDrawable对象资源
<!-- 使用StateListDrawable资源 --> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="@drawable/my_stateListDrawable"/>
4.3 LayerDrawable资源
LayerDrawable对象类似与Flash和Photoshop中的帧的概念,LayerDrawable包含一个Drawable数组,每个Drawable对象类似于一帧,系统会将这些Drawable对象的数组顺序来绘制它们,索引最大的Drawable对象将会被绘制到最上面。
它的使用方法如下:
定义LayerDrawable对象所对应的XML文件
/res/drawable/my_layerDrawable.xml
<?xml version="1.0" encoding="UTF-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 定义轨道的背景 --> <item android:id="@android:id/background" android:drawable="@drawable/grow" /> <!-- 定义轨道上已完成部分的外观--> <item android:id="@android:id/progress" android:drawable="@drawable/ok" /> </layer-list>
引用LayerDrawable对象资源
<!-- 定义一个拖动条,并改变轨道外观 --> <SeekBar android:layout_width="fill_parent" android:layout_height="wrap_content" android:max="100" android:progressDrawable="@drawable/my_layerDrawable"/>
4.4 ShapeDrawable资源
ShapeDrawable用于定义一个基本的几何图形(如矩形、圆形、线条等),定义ShapeDrawable的XML文件的根元素是<shape.../>
,该元素通过指定各种各样的属性改变Shape形状。
它的使用方法如下:
定义ShapeDrawable对象所对应的XML文件
/res/drawable/my_shapeDrawable.xml
<?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <!-- 设置填充颜色 --> <solid android:color="#fff"/> <!-- 设置四周的内边距 --> <padding android:bottom="7dp" android:left="7dp" android:right="7dp" android:top="7dp"/> <!-- 设置边框 --> <stroke android:width="3dip" android:color="#ff0"/> </shape>
引用ShapeDrawable对象资源
<!--背景色为xml--> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="@drawable/my_shapeDrawable"/>
4.5 ClipDrawable资源
ClipDrawable 代表从其他位图上截取的一个“图片片段”,它有三个重要属性:
- android:drawable:指定截取的源Drawable对象
- android:clipOrientation:指定截取方向,可设置为水平或垂直截取
- android:gravity:指定截取时的对齐方式
需要注意的是ClipDrawable是根据level的大小来设置截取的区域大小,官方文档的note中提到:The drawable is clipped completely and not visible when the level is 0 and fully revealed when the level is 10,000。也就是level的大小从0到10000,level为0时完全不显示,为10000时完全显示。是用Drawable提供的setLevel(int level)方法来设置剪切区域。
它的使用方法如下:
定义ClipDrawable对象所对应的XML文件
/res/drawable/my_clipDrawable.xml
<?xml version="1.0" encoding="UTF-8"?> <clip xmlns:android="http://schemas.android.com/apk/res/android" android:clipOrientation="vertical" android:drawable="@drawable/shuangta" android:gravity="top"> </clip>
引用ShapeDrawable对象资源
<ImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitStart" android:src="@drawable/my_clipDrawable"/>
设置Level以控制截取的区域大小
ImageView imageview = (ImageView) findViewById(R.id.image); // 获取图片所显示的ClipDrawable对象 final ClipDrawable drawable = (ClipDrawable) imageview.getDrawable(); //设置截取区域 drawable.setLevel(5000);
4.6 AnimationDrawable资源
AnimationDrawable 代表一个动画,Android既支持逐帧动画,也支持通过平移、变换计算出来的补间动画。
4.6.1 补间动画
补间动画与逐帧动画在本质上是不同的,逐帧动画通过连续播放图片来模拟动画的效果,而补间动画则是通过在两个关键帧之间补充渐变的动画效果来实现的。补间动画的优点是可以节省空间。目前Android应用框架支持的补间动画效果有以下5种。具体实现在android.view.animation类库中。
- AlphaAnimation:透明度(alpha)渐变效果,对应标签。
- TranslateAnimation:位移渐变,需要指定移动点的开始和结束坐标,对应标签。
- ScaleAnimation:缩放渐变,可以指定缩放的参考点,对应标签。
- RotateAnimation:旋转渐变,可以指定旋转的参考点,对应标签。
- AnimationSet:组合渐变,支持组合多种渐变效果,对应标签。
补间动画的效果同样可以使用XML语言来定义,这些动画模板文件通常会被放在Android项目的/res/anim/
目录下。
定义补间动画的XML资源文件以<set.../>
元素为根元素,该元素类可以指定以下四个元素:
- alpha:设置透明的的改变
- scale:设置图片进行缩放改变
- translate:设置图片进行位移变换
- rotate:设置图片进行旋转
它的使用方法如下:
定义AnimationDrawable对象所对应的XML文件
/res/anim/my_tween_animation_drawable.xml
<?xml version="1.0" encoding="UTF-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="5000" android:interpolator="@android:anim/linear_interpolator"> <!-- 定义缩放变换 --> <scale android:duration="2000" android:fillAfter="true" android:fromXScale="1.0" android:fromYScale="1.0" android:pivotX="50%" android:pivotY="50%" android:toXScale="1.4" android:toYScale="0.6" /> <!-- 定义位移变换 --> <translate android:duration="2000" android:fromXDelta="10" android:fromYDelta="30" android:toXDelta="130" android:toYDelta="-80" /> </set>
XML中引用AnimationDrawable对象资源
@anim/my_tween_animation_drawable
Java代码控制播放动画
final ImageView image = (ImageView)findViewById(R.id.image); // 加载动画资源 final Animation anim = AnimationUtils.loadAnimation(this, R.anim.my_tween_animation_drawable); // 设置动画结束后保留结束状态 anim.setFillAfter(true); Button bn = (Button) findViewById(R.id.bn); bn.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // 开始动画 image.startAnimation(anim); } });
4.6.2 逐帧动画
逐帧动画通过连续播放图片来模拟动画的效果,一张图片即为一帧,这是一种传统的动画方式,通过一系列不同图片的顺序播放,可以制造出电影一样的效果
推荐用XML文件的方法实现Drawable动画,不推荐在代码中实现。这种XML文件必须存放在工程中 /res/drawable/
目录下。XML文件的指令(即属性)为动画播放的顺序和时间间隔。
在XML文件中元素为根节点,节点定义了每一帧,表示一个drawable资源的帧和帧间隔。下面是一个XML文件的实例:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true">
<item android:drawable="@drawable/rocket_thrust1" android:duration="200" />
<item android:drawable="@drawable/rocket_thrust2" android:duration="200" />
<item android:drawable="@drawable/rocket_thrust3" android:duration="200" />
</animation-list>
这个动画只会展示3帧的动画,通过设置android:oneshot属性为true,动画只会播放一次然后就停止,并且会一直显示最后一张图片。如果我们设置成false,那么动画就会一直循环播放。
说了这么多,它的使用方法如下:
定义逐帧动画资源对应的xml文件
/res/drawable/my_frame_animation_drawable.xml
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="true"> <item android:drawable="@drawable/ok" android:duration="200"/> <item android:drawable="@drawable/grow" android:duration="200"/> <item android:drawable="@drawable/ic_launcher" android:duration="200"/> </animation-list> <!-- oneshot :是否只播放一遍动画 true 播放一遍 false 循环播放 默认就是false -->
XML中引用该AnimationDrawable对象资源
<ImageView android:id="@+id/imageView1" android:layout_width="match_parent" android:layout_height="300dp" android:layout_alignParentLeft="true" android:background="@drawable/my_frame_animation_drawable"/>
或者代码中赋值
ImageView rocketImage = (ImageView) findViewById(R.id.imageView1); rocketImage.setBackgroundResource(R.drawable.my_frame_drawable);
Java代码播放动画
ImageView rocketImage = (ImageView) findViewById(R.id.imageView1); AnimationDrawable rocketAnimation = (AnimationDrawable) rocketImage.getBackground(); // 先停止播放动画 rocketAnimation.stop(); // 启动动画 rocketAnimation.start();
5. 属性动画
自Android 3.0版本开始,系统给我们提供了一种全新的动画模式,属性动画(property animation),它的功能非常强大,弥补了之前补间动画的一些缺陷,几乎是可以完全替代掉补间动画了。
新引入的属性动画机制已经不再是针对于View来设计的了,也不限定于只能实现移动、缩放、旋转和淡入淡出这几种动画操作,同时也不再只是一种视觉上的动画效果了。它实际上是一种不断地对值进行操作的机制,并将值赋值到指定对象的指定属性上,可以是任意对象的任意属性。所以我们仍然可以将一个View进行移动或者缩放,但同时也可以对自定义View中的Point对象进行动画操作了。我们只需要告诉系统动画的运行时长,需要执行哪种类型的动画,以及动画的初始值和结束值,剩下的工作就可以全部交给系统去完成了。
以下几篇博客对属性动画写得非常好:
Android属性动画完全解析(上),初识属性动画的基本用法
Android属性动画完全解析(中),ValueAnimator和ObjectAnimator的高级用法