六、Android应用的资源
1 资源的类型及存储方式
2 使用字符串、颜色、尺寸资源
3 数组(Array)资源
4 使用(Drawable)资源
5 属性动画(Property Animation)资源
6 使用原始XML资源
7 使用布局(Layout)资源
8 使用菜单(Menu)资源
9 样式(Style)和主题(Theme)资源
10 属性(Attribute)资源
11 使用原始资源
12 国际化和资源自适应
13 自适应不同屏幕的资源
6.1 资源的类型及存储方式
◆ 无法通过R清单类访问的原生资源,保存在assets目录下。
◆ 可通过R资源清单类访问的资源,保存在res目录下。
【Android应用资源的存储】
/res/animator/ 存放定义属性动画的XML文件
/res/anim/ 存放定义补间动画的XML文件
/res/drawable/ 该目录下存放各种位图文件(如png, .9.png, jpg, gif)等。除此之外也能编译如下各种Drawable对象的XML文件:
# BitmapDrawable
# NinePatchDrawable
# StateListDrawable
# ShapeDrawable
# AnimationDrawable
# Drawable的其他各种子类的对象
xml标签名称 类名称 说明
<animation-list> AnimationDrawable 建立由多个图像文件组成的动画,可以用来当成view对象的背景
<bitmap> BitmapDrawable 可以让图像重复排列并适当地缩放和对齐
<clip> ClipDrawable 用来剪裁Drawable对象
<color> ColorDrawable 用来填上颜色
<rotate> RotateDrawable 让Drawable对象旋转一个角度
<scale> ScaleDrawable 缩放Drawable物件
<shape> GradientDrawable 绘制特定形状,注意<shape>的对应类不是ShapeDrawable类
<transition> TransitionDrawable 以淡入淡出的方式轮流显示一组图像
---------------------
drawable-ldpi(低分辨率)
drawable-mdpi(中等分辨率)
drawable-hdpi(高分辨率)
drawable-xhdpi(超高分辨率)
大部分程序、系统将会选择drawable-mdpi目录下的图片,如果系统使用高分屏,那么系统将会选择drawable-hdpi
目录下的图片文件。
/res/raw/
该目录下存放任意类型的原生资源(音频、视频文件等).在Java代码中可通过调用Resources对象的
openRawResource(int id)来获取该资源的二进制输入流,实际上,如果应用程序需要使用原生资源,
推荐把这些原生资源保存到/assets目录下,然后在应用程序中使用AssetManager来访问这些资源。
/res/values/
# arrays.xml 定义数组资源。
# colors.xml 定义原色值资源。
# dimens.xml 定义尺寸值资源。
# strings.xml 定义字符串资源。
# styles.xml 定义样式资源。
6.2 使用字符串、颜色、尺寸资源
(1)在Java代码中使用资源清单项(R)。
1 // 从drawable中加载图片,并设为该窗口的背景。
2 getWindow().setBackgroundDrawableResource(R.drawable.back);
3 // 从string中获取指定字符串资源,并设置该窗口的标题。
4 getWindow().setTitle(getResources().getText(R.string.title));
5 // 获取指定TextView组件,并设置该组件显示string资源中的指定字符串资源。
6 TextView msg = (TextView) findViewById(R.id.msg);
7 msg.setText(R.string.message);
(2)在Java代码中访问实际资源。
Resources主要提供了如下两类方法:
* getXxx(int id):根据资源清单ID来获取实际资源。
* getAssets():获取访问/assets/目录下资源的AssetManager对象。
范例:通过Resources获取实际字符串资源。
Resources res = getResources();
String title = res.getText(R.string.title);
Drawable logo = res.getDrawable(R.drawable.logo);
// 获取数组资源
int[] arr = res.getIntArray(R.array.books);
字符串资源 /res/values/strings.xml
颜色资源 /res/values/colors.xml
尺寸资源 /res/values/dimens.xml
【颜色值定义】
Android中的原色是通过红(Red)、绿(Green)、蓝(Blue)、三原色,以及一个透明度(Alpha)值来表示。颜色值总是以#开头,
接下来就是Alpha-Red-Green-Blue的形式。其中Alpha值可以省略,如果省略了Alpha值,那么该颜色默认是完全不透明的。
Android颜色值支持常见的4中形式:
◆ #RGB:分别指定红、绿、蓝三原色的值(只支持0-f这16级颜色)来代表颜色。
◆ #ARGB:分别指定红、绿、蓝三原色的值(只支持0-f这16级颜色)及透明度(只支持0-f这16级透明度)来代表颜色。
◆ #RRGGBB:分别指定红、绿、蓝三原色的值(支持00-ff这256级颜色)来代表颜色。
◆ #AARRGGBB:分别指定红、绿、蓝三原色的值(支持00-ff这256级颜色)以及透明度(支持00-ff这256级透明度)来代表颜色。
上面4中形式中,A、R、G、B都代表一个十六进制的数。
A代表透明度;R代表红色数值;
G代表绿色数值;B代表蓝色数值。
范例:使用字符串、颜色、尺寸资源
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal">
<!-- 定义一个GridView组件,使用尺度资源中定义的长度来指定水平间距、垂直间距 -->
<GridView
android:id="@+id/grid01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:horizontalSpacing="@dimen/spacing"
android:verticalSpacing="@dimen/spacing"
android:numColumns="3"
android:gravity="center" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="spacing">8dp</dimen>
<!-- 定义GridView组件中每个单元格的宽度、高度 -->
<dimen name="cell_width">60dp</dimen>
<dimen name="cell_height">66dp</dimen>
<!-- 定义主程序的标题的字体大小 -->
<dimen name="title_font_size">18sp</dimen>
</resources>
1 public class ValuesResTest extends Activity { 2 // 使用字符串资源 3 int[] textIds = new int[] { R.string.c1, R.string.c2, R.string.c3, 4 R.string.c4, R.string.c5, R.string.c6, R.string.c7, R.string.c8, 5 R.string.c9 }; 6 // 使用颜色资源 7 int[] colorIds = new int[] { R.color.c1, R.color.c2, R.color.c3, 8 R.color.c4, R.color.c5, R.color.c6, R.color.c7, R.color.c8, 9 R.color.c9 }; 10 11 @Override 12 public void onCreate(Bundle savedInstanceState) { 13 super.onCreate(savedInstanceState); 14 setContentView(R.layout.main); 15 // 创建一个BaseAdapter对象 16 BaseAdapter ba = new BaseAdapter() { 17 @Override 18 public int getCount() { 19 // 指定一共包含9个选项 20 return textIds.length; 21 } 22 @Override 23 public Object getItem(int position) { 24 // 返回指定位置的文本 25 return getResources().getText(textIds[position]); 26 } 27 @Override 28 public long getItemId(int position) { 29 return position; 30 } 31 32 // 重写该方法,该方法返回的View将作为的GridView的每个格子 33 @Override 34 public View getView(int position, View convertView, ViewGroup parent) { 35 TextView text = new TextView(ValuesResTest.this); 36 Resources res = ValuesResTest.this.getResources(); 37 // 使用尺度资源来设置文本框的高度、宽度 38 text.setWidth((int) res.getDimension(R.dimen.cell_width)); 39 text.setHeight((int) res.getDimension(R.dimen.cell_height)); 40 // 使用字符串资源设置文本框的内容 41 text.setText(textIds[position]); 42 // 使用颜色资源来设置文本框的背景色 43 text.setBackgroundResource(colorIds[position]); 44 text.setTextSize(20); 45 text.setTextSize(getResources().getInteger(R.integer.font_size)); 46 return text; 47 } 48 }; 49 GridView grid = (GridView) findViewById(R.id.grid01); 50 // 为GridView设置Adapter 51 grid.setAdapter(ba); 52 } 53 }

6.3 数组(Array)资源
Android 采用位于/res/values/目录下的arrays.xml文件来定义数组,定义数组时XML资源文件的跟元素也是<resources.../>元素,
该元素内可包含如下三种子元素。
# <array.../>子元素:定义普通类型的数组,例如Drawable数组。
# <string-array.../>子元素:定义字符串数组。
# <integer-array.../>子元素:定义证书数组。
Java程序访问到实际数组,Resources提供了如下方法:
# String[] getStringArray(int id):根据资源文件中的字符串数组资源的名称来获取实际的字符串数组。
# int[] getIntArray(int id):根据资源文件中整型数组资源的名称来获取实际的整型数组。
# TypedArray obtainTypedArray(int id):根据资源文件中普通数组资源的名称来获取实际的普通数组。
TypedArray代表了一个通用类型的数组,该类提供了getXxx(int index)来获取指定索引处的数组元素。
1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 <!-- 定义一个Drawable数组 --> 4 <array name="plain_arr"> 5 <item>@color/c1</item> 6 <item>@color/c2</item> 7 <item>@color/c3</item> 8 </array> 9 <!-- 定义字符串数组 --> 10 <string-array name="string_arr"> 11 <item>@string/c1</item> 12 <item>@string/c2</item> 13 <item>@string/c3</item> 14 </string-array> 15 <!-- 定义字符串数组 --> 16 <string-array name="books"> 17 <item>百度网站</item> 18 <item>谷歌网站</item> 19 <item>搜狐网站</item> 20 </string-array> 21 </resources>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal"
android:orientation="vertical" >
<!-- 使用字符串资源,尺度资源 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/app_name"
android:textSize="@dimen/title_font_size" />
<!-- 定义一个GridView组件,使用尺度资源中定义的长度来指定水平间距、垂直间距 -->
<GridView
android:id="@+id/grid01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:horizontalSpacing="@dimen/spacing"
android:numColumns="3"
android:verticalSpacing="@dimen/spacing" />
<!-- 定义ListView组件,使用了数组资源 -->
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:entries="@array/books" />
</LinearLayout>
1 public class ArrayResTest extends Activity {
2 String[] texts; // 获取系统定义的数组资源
3
4 @Override
5 public void onCreate(Bundle savedInstanceState) {
6 super.onCreate(savedInstanceState);
7 setContentView(R.layout.main);
8 texts = getResources().getStringArray(R.array.string_arr);
9 // 创建一个BaseAdapter对象
10 BaseAdapter ba = new BaseAdapter() {
11 @Override
12 public int getCount() {
13 // 指定一共包含9个选项
14 return texts.length;
15 }
16 @Override
17 public Object getItem(int position) {
18 // 返回指定位置的文本
19 return texts[position];
20 }
21 @Override
22 public long getItemId(int position) {
23 return position;
24 }
25 // 重写该方法,该方法返回的View将作为的GridView的每个格子
26 @Override
27 public View getView(int position, View convertView, ViewGroup parent) {
28 TextView text = new TextView(ArrayResTest.this);
29 Resources res = ArrayResTest.this.getResources();
30 // 使用尺度资源来设置文本框的高度、宽度
31 text.setWidth((int) res.getDimension(R.dimen.cell_width));
32 text.setHeight((int) res.getDimension(R.dimen.cell_height));
33 // 使用字符串资源设置文本框的内容
34 text.setText(texts[position]);
35 TypedArray icons = res.obtainTypedArray(R.array.plain_arr);
36 // 使用颜色资源来设置文本框的背景色
37 text.setBackgroundDrawable(icons.getDrawable(position));
38 text.setTextSize(20);
39 return text;
40 }
41 };
42 GridView grid = (GridView) findViewById(R.id.grid01);
43 // 为GridView设置Adapter
44 grid.setAdapter(ba);
45 }
46 }

6.4 使用(Drawable)资源
【StateListDrawable】用于组织多个Drawable对象,当使用StateListDrawable作为目标组件的背景、前景图片时,
StateListDrawable对象所显示的Drawable对象会随目标组件状态的改变而自动切换。
定义StateListDrawable对象的XML的跟元素为<selector.../>,该元素可以包含多个<item.../>元素,该元素可指定如下属性:
# android:color或android:drawable:指定颜色或Drawable对象。
# android:state_xxx:指定一个特定状态。
★☆★ StateListDrawable支持的状态 ★☆★
android:state_active 代表是否处于激活状态
android:state_checkable 代表是否处于勾选状态
android:state_checked 代表是否处于已勾选状态
android:state_enabled 代表是否处于可用状态
android:state_first 代表是否处于开始状态
android:state_focused 代表是否处于已得到焦点状态
android:state_last 代表是否处于结束状态
android:state_middle 代表是否处于中间状态
android:state_pressed 代表是否处于已被按下状态
android:state_selected 代表是否处于已被选中状态
android:state_window_focused 代表是否窗口已得到焦点状态
范例:高亮显示正在输入的文本框
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 android:layout_width="fill_parent" 5 android:layout_height="fill_parent" 6 android:orientation="vertical" > 7 <!-- 使用StateListDrawable资源 --> 8 <EditText 9 android:layout_width="fill_parent" 10 android:layout_height="wrap_content" 11 android:textColor="@drawable/my_image" /> 12 <EditText 13 android:layout_width="fill_parent" 14 android:layout_height="wrap_content" 15 android:textColor="@drawable/my_image" /> 16 </LinearLayout>
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 指定获得焦点时的颜色 -->
<item android:state_focused="true" android:color="#f44"/>
<!-- 指定失去焦点时的颜色 -->
<item android:state_focused="false" android:color="#eee"/>
</selector>


不仅可以让文本框里文字的颜色随文本框状态的改变而切换,也可让按钮的背景图片随按钮状态的改变而切换。
【LayerDrawable】
LayerDrawable可包含一个Drawable数组,因此系统将会按这些Drawable对象的数组顺序来绘制它们,索引最大的Drawable对象将会被绘制在最上面。
定义LayerDrawable对象的XML文件的跟元素为<layer-list.../>,该元素可以包含多个<item.../>元素,该元素可指定如下属性。
# android:drawable:指定作为LayerDrawable元素之一的Drawable对象。
# android:id:为该Drawable对象指定一个标识。
# android:button|top|left|button:它们用于指定一个长度值,用于指定将该Drawable对象绘制到目标组件的指定位置。
范例:定制拖动条的外观
前面知道,使用SeekBar时可指定一个android:progressDrawable属性,该属性可改变SeekBar的外观,借助于
LayerDrawable即可改变SeekBar的规定、已完成部分的Drawable对象。
a)定义如下Drawable资源,my_bar.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>
b)定义三个“层叠”在一起的Drawable对象,layout_logo.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<bitmap
android:gravity="center"
android:src="@drawable/ic_launcher" />
</item>
<item
android:left="25dp" android:top="25dp">
<bitmap
android:gravity="center"
android:src="@drawable/ic_launcher" />
</item>
<item
android:left="50dp" android:top="50dp">
<bitmap
android:gravity="center"
android:src="@drawable/ic_launcher" />
</item>
</layer-list>
c)布局文件。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<!-- 定义一个拖动条,并改变轨道外观 -->
<SeekBar
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:max="100"
android:progressDrawable="@drawable/my_bar" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/layout_logo" />
</LinearLayout>

【ShapeDrawable】
用于定义一个基本的几何图形(矩形、圆形、线条等),定义ShapeDrawable的XML文件的跟元素是<shape.../>元素,
该元素可指定如下属性:
http://jingyan.baidu.com/article/86112f13513f4127379787b0.html
android:shape=["rectangle"|"oval"|"line"|"ring"]:指定定义哪种类型的几何图形。
定义ShapeDrawable对象的完整语法格式如下:
<?xml version="1.0" encoding="utf-8"?>
<scale
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/drawable_resource"
android:scaleGravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
"fill_vertical" | "center_horizontal" | "fill_horizontal" |
"center" | "fill" | "clip_vertical" | "clip_horizontal"]
android:scaleHeight="percentage"
android:scaleWidth="percentage" />
范例:椭圆形、渐变背景的文本框
/drawable-mdpi/my_shape_1.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:left="7dp" android:top="7dp" android:right="7dp" android:bottom="7dp" /> <!-- 设置边框 --> <stroke android:width="3dip" android:color="#ff0" /> </shape>
/drawable-mdpi/my_shape_2.xml
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 定义填充渐变颜色 -->
<gradient
android:startColor="#FFFF0000"
android:endColor="#80FF00FF"
android:angle="45"/>
<!-- 设置内填充 -->
<padding android:left="7dp"
android:top="7dp"
android:right="7dp"
android:bottom="7dp" />
<!-- 设置圆角矩形 -->
<corners android:radius="8dp" />
</shape>
/drawable-mdpi/my_shape_3.xml
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<!-- 定义填充渐变颜色 -->
<gradient
android:startColor="#ff0"
android:endColor="#00f"
android:angle="45"
android:type="sweep"/>
<!-- 设置内填充 -->
<padding android:left="7dp"
android:top="7dp"
android:right="7dp"
android:bottom="7dp" />
<!-- 设置圆角矩形 -->
<corners android:radius="8dp" />
</shape>
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/my_shape_1" />
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/my_shape_2" />
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/my_shape_3" />
</LinearLayout>

【ClipDrawable】
代表从其他位图上截取一个“图片片段”,在XML中定义ClipDrawable使用<clip.../>,该元素的语法为:
上面的语法格式中可指定如下三个属性:
@ android:drawable:指定截取Drawable对象。
@ android:clipOrientation:指定截取方向,可设置水平截取或垂直截取。
@ android:gravity:指定攫取时的对其方式。
使用ClipDrawable对象时可调用setLevel(int level)来设置攫取的区域大小,当level为0时,
截取的图片片段为空;当level为10000时,截取整张图片。
范例:徐徐展开的图片
因为ClipDrawable对象可调用setLevel(int level)控制截取图片的部分,因此只要设置一个定时器,让程序不断
调用ClipDrawable的setLevel(int level)即可实现图片徐徐展开的效果。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ImageView
android:id="@+id/image"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scaleType="fitStart"
android:src="@drawable/my_clip" />
</LinearLayout>
<?xml version="1.0" encoding="UTF-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/shuangta"
android:clipOrientation="horizontal"
android:gravity="center">
</clip>
程序先定义一个ClipDrawable对象对象,上面的程序控制从中间开始截取图片,截取方向为水平截取。
接下来程序将通过一个定时器来定期修改ClipDrawable对象的level,即可实现图片徐徐张开的效果。
1 public class ClipDrawableTest extends Activity { 3 private ClipDrawable drawable = null; 4 5 final Handler handler = new Handler() { 6 @Override 7 public void handleMessage(Message msg) { 8 // 如果该消息是本程序所发送的 9 if (msg.what == 0x1233) { 10 // 修改ClipDrawable的level值 11 drawable.setLevel(drawable.getLevel() + 200); 12 } 13 } 14 }; 15 16 @Override 17 public void onCreate(Bundle savedInstanceState) { 18 super.onCreate(savedInstanceState); 19 setContentView(R.layout.main); 20 ImageView imageview = (ImageView) findViewById(R.id.image); 21 // 获取图片所显示的ClipDrawable对象 22 drawable = (ClipDrawable) imageview.getDrawable(); 23 24 final Timer timer = new Timer(); 25 timer.schedule(new TimerTask() { 26 @Override 27 public void run() { 28 Message msg = new Message(); 29 msg.what = 0x1233; 30 // 发送消息,通知应用修改ClipDrawable对象的level值。 31 handler.sendMessage(msg); 32 // 取消定时器 33 if (drawable.getLevel() >= 10000) { 34 timer.cancel(); 35 } 36 } 37 }, 0, 300); 38 } 39 }

【AnimationDrawable】
Android既支持传统的帧动画(电影方式,一张张切换),也支持通过平移、变换计算出来的补间动画。
定义补间动画的XML资源文件以<set.../>元素作为根元素,该元素内可以指定如下4个元素:
@ alpha:设置透明度的改变。
@ scale:设置图片进行缩放改变。
@ translate:设置图片进行位移变换。
@ rotate:设置图片进行旋转。
定义动画的XML资源应该放在/res/anim路径下。
定义补间动画的思路很简单:设置一张图片的开始状态(透明度、位置、缩放比、旋转度)、并设置该图片
的结束状态(透明度、位置、缩放比、旋转度),再设置动画的持续时间,Android系统会使用动画效果把这
张图片从开始状态变换到结束状态。
设置补间动画的语法格式如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@[package:]anim/interpolator_resource"
android:shareInterpolator=["true" | "false"]
android:duration="持续时间">
<alpha
android:fromAlpha="float"
android:toAlpha="float" />
<scale
android:fromXScale="float"
android:toXScale="float"
android:fromYScale="float"
android:toYScale="float"
android:pivotX="float"
android:pivotY="float" />
<translate
android:fromXDelta="float"
android:toXDelta="float"
android:fromYDelta="float"
android:toYDelta="float" />
<rotate
android:fromDegrees="float"
android:toDegrees="float"
android:pivotX="float"
android:pivotY="float" />
<set>
...
</set>
</set>
fromXxx,toXxx:这些属性就用于定义图片的开始状态、结束状态。
除此之外 scale缩放变化, rotate旋转变换 时,还需要指定如下
pivotX、pivotY两个属性。这两个属性用于指定变换的"中心点"
---比如进行旋转变换时,需要指定"旋轴点";进行缩放变换时,
需要指定"中心点"。
上面<set.../>、<alpha.../>、<scale.../>、<translate.../>、<rotate.../>都可指定一个
android:interpolator属性,该属性指定动画的变化速度,可以实现匀速、正速度、负速度、
无规则变加速等,Android系统的R.anim类中包含了大致常量,它们定义了不同的动画速度。
例如:
linear_interpolator:匀速变换。
accelerate_interpolator:加速变换。
decelerate_interpolator:减速变换。
如果程序想让<set.../>元素下所有的变换效果使用相同的动画速度,则可指定
android:shareInterpolator="true"。
<?xml version="1.0" encoding="UTF-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator"
android:duration="5000">
<!-- 定义缩放变换 -->
<scale android:fromXScale="1.0"
android:toXScale="1.4"
android:fromYScale="1.0"
android:toYScale="0.6"
android:pivotX="50%"
android:pivotY="50%"
android:fillAfter="true"
android:duration="2000" />
<!-- 定义位移变换 -->
<translate android:fromXDelta="10"
android:toXDelta="130"
android:fromYDelta="30"
android:toYDelta="-80"
android:duration="2000" />
</set>
为了在Java代码中获取实际的Animation对象,则可调用AnimationUtils方法如下:
loadAnimation(Context ctx, int resId)
1 public class AnimationDrawable extends Activity { 2 @Override 3 public void onCreate(Bundle savedInstanceState) { 4 super.onCreate(savedInstanceState); 5 setContentView(R.layout.main); 6 final ImageView image = (ImageView) findViewById(R.id.image); 7 // 加载动画资源 8 final Animation anim = AnimationUtils.loadAnimation(this, 9 R.anim.my_anim); 10 // 设置动画结束后保留结束状态 11 anim.setFillAfter(true); 12 Button bn = (Button) findViewById(R.id.bn); 13 bn.setOnClickListener(new OnClickListener() { 14 @Override 15 public void onClick(View arg0) { 16 // 开始动画 17 image.startAnimation(anim); 18 } 19 }); 20 } 21 }
6.5 属性动画(Property Animation)资源
Animator代表一个属性动画,但它只是一个抽象类,通常会使用它的子类:AnimatorSet、ValueAnimator、ObjectAnimator、
TimeAnimator。
定义属性动画的XML资源文件能以如下三个元素中的任意一个作为根元素。
@ <set.../>:它是一个父元素,用于包含其他<objectAnimator.../>、<animator.../>或<set.../>子元素,
该元素定义的资源代表AnimatorSet对象。
@ <objectAnimator.../>:用于定义ObjectAnimator动画。
@ <animator.../>:用于定义ValueAnimator动画。
定义属性动画的语法格式如下:
<set
android:ordering=["together" | "sequentially"]>
<objectAnimator
android:propertyName="string"
android:duration="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:valueType=["intType" | "floatType"]/>
<animator
android:duration="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:valueType=["intType" | "floatType"]/>
<set>
...
</set>
</set>
范例:不断渐变的背景色(使用属性动画来控制组件背景色不断渐变)
R.animator.color_anim
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="backgroundColor"
android:duration="3000"
android:valueFrom="#FF8080"
android:valueTo="#8080FF"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:valueType="intType">
</objectAnimator>
AnimatorTest.java 类文件
public class AnimatorTest extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout container = (LinearLayout) findViewById(R.id.container);
// 添加MyAnimationView组件
container.addView(new MyAnimationView(this));
}
public class MyAnimationView extends View {
public MyAnimationView(Context context) {
super(context);
// 加载动画资源
ObjectAnimator colorAnim = (ObjectAnimator) AnimatorInflater
.loadAnimator(AnimatorTest.this, R.animator.color_anim);
colorAnim.setEvaluator(new ArgbEvaluator());
// 对该View本身应用属性动画
colorAnim.setTarget(this);
// 开始指定动画
colorAnim.start();
}
}
}
6.6 使用原始XML资源
6.7 使用布局(Layout)资源
6.8 使用菜单(Menu)资源
6.9 样式(Style)和主题(Theme)资源
一个样式相当于多个格式的集合,其他UI组件通过style属性来指定样式,这就相当于把该样式包含的所有格式
同时应用于该UI组件。
Android的样式资源文件放在/res/values目录下,样式资源文件的跟元素是<resources.../>元素,该元素内可
包含过个<style.../>子元素,每个<style.../>元素定义一个样式。
<style.../>元素指定如下两个属性:
name:指定样式的名称。
parent:指定该样式所继承的父样式。当继承某个父样式时,该样式将会获得父样式中定义的全部格式。
当然,当前样式也可以覆盖父样式中指定的格式。
my_style.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <resources> 3 <!-- 定义一个样式,指定字体大小、字体颜色 --> 4 <style name="style1"> 5 <item name="android:textSize">20sp</item> 6 <item name="android:textColor">#00d</item> 7 </style> 8 <!-- 定义一个样式,继承前一个颜色 --> 9 <style name="style2" parent="@style/style1"> 10 <item name="android:background">#ee6</item> 11 <item name="android:padding">8dp</item> 12 <!-- 覆盖父样式中指定的属性 --> 13 <item name="android:textColor">#000</item> 14 </style> 15 <style name="CrazyTheme"> 16 <item name="android:windowNoTitle">true</item> 17 <item name="android:windowFullscreen">true</item> 18 <item name="android:windowFrame">@drawable/window_border</item> 19 <item name="android:windowBackground">@drawable/star</item> 20 </style> 21 </resources>
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<!-- 指定使用style1的样式 -->
<EditText
style="@style/style1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/style1" />
<!-- 指定使用style2的样式 -->
<EditText
style="@style/style2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/style2" />
</LinearLayout>

与样式资源非常相似,主题资源的XML文件通常也放在/res/values目录下。主题资源的XML文档同样以<resource.../>元素
作为跟元素,同样使用<style.../>元素来定义主题。
与样式的区别主要体现在:
1)主题不能作用与单个的View组件,主体应该对整个应用中的所有Activity起作用,或对指定的Activity起作用。
2)主题定义的格式应该是改变窗口外观的格式,例如窗口标题、窗口边框等。
范例:给所有的窗口添加边框、背景(图6.10)
为了给所有窗口都添加边框、背景,先在/res/values/my_style.xml文件中增加一个主题,
定义主体的<style.../>片段如下:
<style name="CrazyTheme">
<item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowFrame">@drawable/window_border</item>
<item name="android:windowBackground">@drawable/star</item>
</style>
其中@drawable/star是一张图片;@drawable/window_border是一个ShapeDrawable资源。
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 设置填充颜色 -->
<solid android:color="#0fff"/>
<!-- 设置四周的内边距 -->
<padding android:left="7dp"
android:top="7dp"
android:right="7dp"
android:bottom="7dp" />
<!-- 设置边框 -->
<stroke android:width="10dip" android:color="#f00" />
</shape>
定义了上面的主题之后,接下来即可在Java代码中使用该主题,例如如下代码:
在onCreate中调用,setTheme(R.style.CrazyTheme);
大部分时候,在AndroidManifest.xml文件中对指定应用、指定Activity应用主题更加简单。
如果我们想让应用中全部窗口使用该主题,只要为<application.../>元素添加android:theme属性。
属性值是一个主题的名字,如下所示:
<application android:theme="@style/CrazyitTheme">
...
</application>
Android中提供了几种内置的主题资源,这些主题通过查询Android.R.style类可以看到。例如前面介绍的对话框
风格的窗口,我们只要采用如下代码来定义某个Activity即可。
<activity android:theme="@android:style/Theme.Dialog">
...
</activity>
与样式类似的是,Android主题同样支持继承。如果开发过程中还想利用某个主题。但需要对它进行局部修改,
则可通过继承系统主题来实现自定义主题,例如如下代码片段:
<style name="CrazyTheme" parent="@android:style/Theme.Dialog">
...</activity>
6.10 属性(Attribute)资源

/res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 定义一个属性 -->
<attr name="duration"></attr>
<!-- 定义一个styleable对象来组合多个属性 -->
<declare-styleable name="AlphaImageView">
<attr name="duration"/>
</declare-styleable>
</resources>
【提示】在属性资源中定义<declare-styleable.../>元素时,也可在其内部直接使用<attr.../>定义属性,
使用<attr../>时指定一个format属性即可,例如上面我们可以指定<attr name="duration" format="integer"/>。
1 public class AlphaImageView extends ImageView {
2 // 图像透明度每次改变的大小
3 private int alphaDelta = 0;
4 // 记录图片当前的透明度。
5 private int curAlpha = 0;
6 // 每隔多少毫秒透明度改变一次
7 private final int SPEED = 300;
8 Handler handler = new Handler() {
9 @Override
10 public void handleMessage(Message msg) {
11 if (msg.what == 0x123) {
12 // 每次增加curAlpha的值
13 curAlpha += alphaDelta;
14 if (curAlpha > 255)
15 curAlpha = 255;
16 // 修改该ImageView的透明度
17 AlphaImageView.this.setAlpha(curAlpha);
18 }
19 }
20 };
21
22 public AlphaImageView(Context context, AttributeSet attrs) {
23 super(context, attrs);
24 TypedArray typedArray = context.obtainStyledAttributes(attrs,
25 R.styleable.AlphaImageView);
26 // 获取duration参数
27 int duration = typedArray
28 .getInt(R.styleable.AlphaImageView_duration, 0);
29 // 计算图像透明度每次改变的大小
30 alphaDelta = 255 * SPEED / duration;
31 }
32
33 @Override
34 protected void onDraw(Canvas canvas) {
35 this.setAlpha(curAlpha);
36 super.onDraw(canvas);
37 final Timer timer = new Timer();
38 // 按固定间隔发送消息,通知系统改变图片的透明度
39 timer.schedule(new TimerTask() {
40 @Override
41 public void run() {
42 Message msg = new Message();
43 msg.what = 0x123;
44 if (curAlpha >= 255) {
45 timer.cancel();
46 } else {
47 handler.sendMessage(msg);
48 }
49 }
50 }, 0, SPEED);
51 }
52 }
代码中的R.styleable.AlphaImageView、R.styleable.AlphaImageView_duration都是Android SDK根据
属性资源文件自动生成的。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:crazyit="http://schemas.android.com/apk/res/org.crazyit.res"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<!-- 使用自定义组件,并指定属性资源中定义的属性 -->
<org.crazyit.res.AlphaImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="@drawable/ee"
crazyit:duration="60000" />
</LinearLayout>
crazyit:duration助兴位于“http://schemas.android.com/apk/res/ + 项目包名”命名空间下。
6.11 使用原始资源
AssetManager是一个专门管理/assets/目录下原始资源的管理器类,AssetManager提供了如下两个常用方法来访问Asset资源。
inputStream open(String fileName):根据文件名来获取原始资源对应的输入流。
AssetFileDescriptor openFd(String fileName):根据文件名来获取原始资源对应的AssetFileDescriptor。
AssetFileDescriptor代表了一项原始资源的描述,应用程序可通过AssetFileDescriptor来获取原始资源。
1 public class RawResTest extends Activity {
2 MediaPlayer mediaRaw = null; // 播放raw声音
3 MediaPlayer mediaAsset = null; // 播放asset声音
4
5 @Override
6 public void onCreate(Bundle savedInstanceState) {
7 super.onCreate(savedInstanceState);
8 setContentView(R.layout.main);
9 // 直接根据声音文件的ID来创建MediaPlayer。
10 mediaRaw = MediaPlayer.create(this, R.raw.bomb);
11 // 获取该应用的AssetManager
12 AssetManager am = getAssets();
13 try {
14 // 获取指定文件对应的AssetFileDescriptor。
15 AssetFileDescriptor afd = am.openFd("shot.mp3");
16 mediaAsset = new MediaPlayer();
17 // 使用MediaPlayer加载指定的声音文件。
18 mediaAsset.setDataSource(afd.getFileDescriptor());
19 mediaAsset.prepare();
20 } catch (IOException e) {
21 e.printStackTrace();
22 }
23 // 获取第一个按钮,并为它绑定事件监听器
24 Button playRaw = (Button) findViewById(R.id.playRaw);
25 playRaw.setOnClickListener(new OnClickListener() {
26 @Override
27 public void onClick(View arg0) {
28 // 播放声音
29 mediaRaw.start();
30 }
31 });
32 // 获取第二个按钮,并为它绑定事件监听器
33 Button playAsset = (Button) findViewById(R.id.playAsset);
34 playAsset.setOnClickListener(new OnClickListener() {
35 @Override
36 public void onClick(View arg0) {
37 // 播放声音
38 mediaAsset.start();
39 }
40 });
41 }
42 }
6.12 国际化和资源自适应
国际化的英文单词是Internationalization,简称I18N,其中I第一个字母,18中间省略的字母个数。
而N代表最后一个字母。
图6.12 Java程序国际化的思路
Java程序的国际化主要通过如下三个类完成:
& java.util.ResourceBundle:用于加载一个国家、语言资源包。
& java.util.Locale:用于封装一个特定的国家/区域、语言环境。
& java.text.MessageFormat:用于格式化带占位符的字符串。
为了实现程序的国际化,必须先提供程序所需的资源文件。资源文件的内容适合很多key-value对。其中key是程序
使用的部分,而value则是程序界面的显示字符串。
资源文件的命名可以有如下三种形式:
& baseName_language_country.properties
& baseName_language.properties
& baseName.properties
其中baseName是资源文件的基本名,用户可以自由定义。
language和country都不可以随意变化,必须是Java所支持的语言和国家。
【Java支持语言和国家】
事实上,Java不可能支持所有的国家和语言,如需获取Java所支持的语言和国家,可调用Locale类的getAvailableLocales方法获取,
该方法返回一个Locale数组,该数组里包含了Java所支持的语言和国家。
public class TestDemo9 {
public static void main(String[] args) {
// 返回Java所支持的全部国家和语言的数组
Locale[] localeList = Locale.getAvailableLocales();
// 遍历数组的每个元素,依次获取所支持的国家和语言
for (int i=0; i<localeList.length; i++) {
System.out.println(localeList[i].getDisplayCountry()
+ "=" + localeList[i].getCountry()
+ "=" + localeList[i].getDisplayLanguage()
+ "=" + localeList[i].getLanguage());
}
}
}
输出结果:
日本=JP=日文=ja
秘鲁=PE=西班牙文=es
==英文=en
日本=JP=日文=ja
巴拿马=PA=西班牙文=es
波斯尼亚和黑山共和国=BA=塞尔维亚文=sr
==马其顿文=mk
危地马拉=GT=西班牙文=es
阿拉伯联合酋长国=AE=阿拉伯文=ar
挪威=NO=挪威文=no
阿尔巴尼亚=AL=阿尔巴尼亚文=sq
==保加利亚文=bg
伊拉克=IQ=阿拉伯文=ar
也门=YE=阿拉伯文=ar
==匈牙利文=hu
葡萄牙=PT=葡萄牙文=pt
塞浦路斯=CY=希腊文=el
卡塔尔=QA=阿拉伯文=ar
马其顿王国=MK=马其顿文=mk
==瑞典文=sv
瑞士=CH=德文=de
美国=US=英文=en
芬兰=FI=芬兰文=fi
==冰岛文=is
==捷克文=cs
马耳他=MT=英文=en
斯洛文尼亚=SI=斯洛文尼亚文=sl
斯洛伐克=SK=斯洛伐克文=sk
==意大利文=it
土耳其=TR=土耳其文=tr
==中文=zh
==泰文=th
沙特阿拉伯=SA=阿拉伯文=ar
==挪威文=no
英国=GB=英文=en
塞尔维亚及黑山=CS=塞尔维亚文=sr
==立陶宛文=lt
==罗马尼亚文=ro
新西兰=NZ=英文=en
挪威=NO=挪威文=no
立陶宛=LT=立陶宛文=lt
尼加拉瓜=NI=西班牙文=es
==荷兰文=nl
爱尔兰=IE=爱尔兰文=ga
比利时=BE=法文=fr
西班牙=ES=西班牙文=es
黎巴嫩=LB=阿拉伯文=ar
==朝鲜文=ko
加拿大=CA=法文=fr
爱沙尼亚=EE=爱沙尼亚文=et
科威特=KW=阿拉伯文=ar
塞尔维亚=RS=塞尔维亚文=sr
美国=US=西班牙文=es
墨西哥=MX=西班牙文=es
苏丹=SD=阿拉伯文=ar
印度尼西亚=ID=印度尼西亚文=in
==俄文=ru
==拉托维亚文(列托)=lv
乌拉圭=UY=西班牙文=es
拉脱维亚=LV=拉托维亚文(列托)=lv
==希伯来文=iw
巴西=BR=葡萄牙文=pt
叙利亚=SY=阿拉伯文=ar
==克罗地亚文=hr
==爱沙尼亚文=et
多米尼加共和国=DO=西班牙文=es
瑞士=CH=法文=fr
印度=IN=印地文=hi
委内瑞拉=VE=西班牙文=es
巴林=BH=阿拉伯文=ar
菲律宾=PH=英文=en
突尼斯=TN=阿拉伯文=ar
==芬兰文=fi
奥地利=AT=德文=de
==西班牙文=es
荷兰=NL=荷兰文=nl
厄瓜多尔=EC=西班牙文=es
台湾地区=TW=中文=zh
约旦=JO=阿拉伯文=ar
==白俄罗斯文=be
冰岛=IS=冰岛文=is
哥伦比亚=CO=西班牙文=es
哥斯达黎加=CR=西班牙文=es
智利=CL=西班牙文=es
埃及=EG=阿拉伯文=ar
南非=ZA=英文=en
泰国=TH=泰文=th
希腊=GR=希腊文=el
意大利=IT=意大利文=it
==加泰罗尼亚文=ca
匈牙利=HU=匈牙利文=hu
==法文=fr
爱尔兰=IE=英文=en
乌克兰=UA=乌克兰文=uk
波兰=PL=波兰文=pl
卢森堡=LU=法文=fr
比利时=BE=荷兰文=nl
印度=IN=英文=en
西班牙=ES=加泰罗尼亚文=ca
摩洛哥=MA=阿拉伯文=ar
玻利维亚=BO=西班牙文=es
澳大利亚=AU=英文=en
==塞尔维亚文=sr
新加坡=SG=中文=zh
==葡萄牙文=pt
==乌克兰文=uk
萨尔瓦多=SV=西班牙文=es
俄罗斯=RU=俄文=ru
韩国=KR=朝鲜文=ko
==越南文=vi
阿尔及利亚=DZ=阿拉伯文=ar
越南=VN=越南文=vi
黑山=ME=塞尔维亚文=sr
==阿尔巴尼亚文=sq
利比亚=LY=阿拉伯文=ar
==阿拉伯文=ar
中国=CN=中文=zh
白俄罗斯=BY=白俄罗斯文=be
香港=HK=中文=zh
==日文=ja
以色列=IL=希伯来文=iw
保加利亚=BG=保加利亚文=bg
==印度尼西亚文=in
马耳他=MT=马耳他文=mt
巴拉圭=PY=西班牙文=es
==斯洛文尼亚文=sl
法国=FR=法文=fr
捷克共和国=CZ=捷克文=cs
瑞士=CH=意大利文=it
罗马尼亚=RO=罗马尼亚文=ro
波多黎哥=PR=西班牙文=es
加拿大=CA=英文=en
德国=DE=德文=de
==爱尔兰文=ga
卢森堡=LU=德文=de
==德文=de
阿根廷=AR=西班牙文=es
==斯洛伐克文=sk
马来西亚=MY=马来文=ms
克罗地亚=HR=克罗地亚文=hr
新加坡=SG=英文=en
==丹麦文=da
==马耳他文=mt
==波兰文=pl
阿曼=OM=阿拉伯文=ar
==土耳其文=tr
泰国=TH=泰文=th
==希腊文=el
==马来文=ms
瑞典=SE=瑞典文=sv
丹麦=DK=丹麦文=da
洪都拉斯=HN=西班牙文=es
【为Android应用提供国际化资源】
不同values文件夹的命名方式为:values-语言代码-r 国家代码。
例如:values-zh-rCN、values-en-rUS。
【提示】如果还需要为drawable目录按分辨率提供文件夹,则可以在后面追加分辨率后缀,
例如drawable-zh-rCN-mdpi、drawable-zh-rCN-hdpi、drawable-zh-rCN-xhdpi、
drawable-en-rUS-mdpi、drawable-en-rUS-hdpi、drawable-en-rUS-xhdpi等。
6.13 自适应不同屏幕的资源
Android默认把drawable目录分别drawable-ldpi、drawable-mdpi、drawable-hdpi、drawable-xhdpi。
通常来说,屏幕资源需要考虑如下两个方面:
● 屏幕尺寸:可分为small(小屏幕)、normal(中等屏幕)、large(大屏幕)、xlarge(超大屏幕)。
● 屏幕分辨率:可分为ldpi(低分辨率)、mdpi(中等分辨率)、hdpi(高分辨率)、xhdpi(超高分辨率)4中。
● 屏幕方向:分为 land(横屏)和port(竖屏)两种。

下面是上面4中屏幕尺寸所需的最低分辨率:
● xlarge 屏幕尺寸至少需要 960dp*720dp。
● large 屏幕尺寸至少需要 640dp*480dp。
● normal 屏幕尺寸至少需要 470dp*320dp。
● small 屏幕尺寸至少需要 426dp*320dp。
为了提供自适应不同屏幕的资源,最简单的做法就是为不同屏幕尺寸、不同屏幕分辨率提供相应的布局资源、Drawable资源。
● 屏幕分辨率:可以为drawable目录增加如下后缀,ldpi(低分辨率),mdpi(中等分辨率),hdpi(高分辨率),
xhdpi(超高分辨率),nodpi(默认分辨率)。分别为不同不分辨率的屏幕提供资源。
● 屏幕尺寸:可以为layout、values等目录增加如下后缀:small, normal, large, xlarge,
分别为不同尺寸的屏幕提供相应资源。
● 屏幕方向:可以为layout、values等目录增加后缀land和port,分别为横屏,竖屏提供相应的资源。
浙公网安备 33010602011771号