Support Different Devices
全世界的Android设备有着各种各样的外形和尺寸。通过各种各样的设备类型,我们有机会使我们的app接触到广大的用户群体。为了能在各种各样的Android设备上使用,我们的app需要适配不同的设备类型。某些重要的因素你应该加以考虑,比如不同的语言,屏幕尺寸以及各种Android系统版本。
Supporting Different Language
把UI中的字符串存储在外部文件,然后通过代码提取,这是一个很好的做法。Android可以通过工程中的一个资源目录轻松的实现这一功能。
如果你使用Android SDK Tools创建工程,tools会在工程的根目录创建一个res/目录,res/目录中是所有资源类型的子目录。也有一些默认的文件,比如res/values/string.xml,用于保存字符串值。
Create Locale Directories and String Files
为了支持更多的语言,在res/中创建额外的values目录,目录名字以连字符和ISO语言代码结尾。比如values-es/是语言代码为“es“的区域设置的简单资源文件的目录。Android会根据设备运行时的区域设置,加载合适的资源。
一旦决定支持语言,就需要创建资源子目录和字符串资源文件。比如:
MyProject/
res/
values/
strings.xml
values-es/
strings.xml
values-fr/
strings.xml
将区域语言字符串值添加到相应的文件中。
在运行时Android系统会基于用户设备当前的区域设置使用相应的字符串资源。
比如,下面是一些不同语言的字符串资源。
English(default),/values/strings.xml:
<resources>
<string name="app_name">My Application</string>
<string name="hello_world">Hello World!</string>
</resources>
Spanish,/values-es/strings.xml:
<resources>
<string name="app_name">Mi Aplicación</string>
<string name="hello_world">Hola Mundo!</string>
</resources>
French,/values-fr/strings.xml:
<resources>
<string name="app_name">Mon Application</string>
<string name="hello_world">Bonjour le monde !</string>
</resources>
Use the String Resource
你可以通过源代码来引用字符串资源,其他XML文件可以通过元素的name属性来引用字符串资源。
在源代码中可以通过R.string.语法来引用一个字符串资源。很多方法都可以通过这种方式来接受字符串资源。
比如:
//Get a string resource from your app's Resources
String hell = getResources().getString(R.string.hello_world);
// Or supply a string resource to a method that requires a string
TextView textView = new TextView(this);
textView.setText(R.string.hello_world);
在其他XML文件中,每当XML属性需要接受一个字符串值时,我们可以通过@string/语法来引用一个字符串资源。
比如:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world"/>
Support Different Screens
Android用尺寸和分辨率两个常规的属性来对设备屏幕进行分类。我们应该预料到我们的app各种屏幕尺寸和分辨率的设备中。这样,我们应该准备一写可选资源,针对不同的屏幕尺寸和分辨率,来优化其外观。
* 四种普遍的尺寸:small,normal,large,xlarge;
* 四种普遍的分辨率:low(ldpi),medium(mdpi),high(hdpi),extra high(xhdpi)
为不同的屏幕定义不同的layouts和bitmaps,我们必须将这些可选的资源放在单独的目录中,就像适配不同的语言那样做。
同时也要注意到屏幕的方向也是一种需要考虑的屏幕尺寸变化,所以许多app需要修改Layout去优化用户在每个方向上的体验。
Create Different Layouts
为了优化在不同屏幕尺寸上的用户体验,我们需要为你想支持的每一个屏幕尺寸创建唯一的layout XML文件。每个布局应该保存在相应的资源目录中。名字以-为后缀。比如,一个大屏幕唯一的布局文件应该保存在res/layout-large/目录下。
为了匹配合适的屏幕Android会自动的测量我们的layout。因此不需要因为不同屏幕尺寸而担心UI元素的大小而应专注于布局结构对用户体验的影响(比如关键视图相对于同级视图的尺寸和位置)。
比如,这个工程包括一个默认布局和一个适配大屏幕的布局:
MyProject/
res/
layout/
main.xml
layout-large/
main.xml
文件名必须完全一样,但是为了向相应的屏幕尺寸提供优化的UI,他们的内容可以不一样。
如平常一样在APP中简单引用layout文件:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
系统会基于app运行时的屏幕尺寸加载相应的layout文件。
另一个例子,这是一个适配横向屏幕的layout:
MyProject/
res/
layout/
main.xml
layout-land/
main.xml
默认情况下,layout/main.xml文件用于纵向屏幕。
如果你想为横向屏幕提供一个专门的布局,同时也适配大屏幕,这时你需要同时使用large和land修饰符:
MyProject/
res/
layout/
main.xml
layout-large/
main.xml
layout-large-land/
main.xml
**Android 3.2及更高版本支持定义屏幕的高级方法,它允许根据屏幕的最小宽度和高度,为各种屏幕指定与密度无关的资源。
Create Different Bitmap
我们应该为四种普遍的分辨率:low,medium,high和extra-high提供相应的bitmap资源。这能使我们的app在所有的屏幕分辨率下都有良好的画质和效果。
要生成这些图像,我们应该从原始的矢量资源开始,根据下列屏幕尺寸,生成各种分辨率的图像:
* xhdpi:2.0
* hdpi:1.5
* mdpi:1.0(基准)
* ldpi:0.75
这意味着如果你要为xhdpi设备生成一张200x200的图片,那么你应该为hdpi生成150x150,为mdpi生成100x100,为ldpi生成75x75的图片资源。
然后将相应的资源文件放在drawable资源目录中:
MyProject/
res/
drawable-xhdpi/
awesomeimage-png
drawable-hdpi/
awesomeimage-png
drawable-mdpi/
awesomeimage-png
drawable-ldpi/
awesomeimage-png
任何时候,你引用@drawable/awesomeimage,系统都会根据屏幕密度选择相应的bitmap资源。
**低密度(ldpi)是非必要的,当你提供了hdpi图像资源时,系统会把hdpi图像的比例缩小一半,去适配ldpi。
Support Different Platform Version
最新的Android系统版本会为我们的app提供更棒的APIs,但我们仍应该支持Android系统的旧版本,直到更多的设备更新到新系统。
Platform Version的面板会定时地更新,通过统计访问Google Play Store的设备数量来显示运行每个系统的Android版本分布。通常,在app更新至最新版本时,先确保新版本的app可以支持90%的设备。
Tip:为了在几个Android版本上提供最好的特性和功能,我们应该在app中使用Support库,它允许我们在旧版本上使用最近几个平台的APIs。
Specify Munimum and Target API Level
AndroidManifest.xml文件描述了我们的app的细节,以及app所支持的Android系统版本。具体来说,元素中的minSdkVersion和targetSdkVersion属性,标明你在设计和测试app时,最低兼容API级别以及最高适用的API级别。
比如:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"...>
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="15" />
...
</manifest>
随着新的Android版本的发布,一些样式或者行为可能会改变。为了使我们的app能够利用这些变化并确保app能够匹配不同风格的用户设备,我们应该将targetSdkVersion属性的值与可获得的最新Android版本匹配。
Check System Version at Runtime
Android在Build常量类中为每个平台版本提供了一个唯一的代号。在我们的App使用这些代号可以建立条件,确保依赖更高API级别的代号,只会在这些API在当前系统可用时才会执行。
private void setUpActionBar() {
// Make sure we're running on Honeycomb or higher to use ActionBar APIs
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
Note:当解析XML资源时,Android会忽略当前设备不支持的XML属性。所以我们可以安全的使用较新的Android版本,而不用当心旧版本遇到这些代号会崩溃。比如:如果我们设置targetSdkVersion=“11”,我们的app包括了Android 3.0及更高版本中的ActionBar。然后向Action Bar中添加菜单项,我们需要在菜单资源文件中设置android:showAsAction=”ifRoom”。在跨版本的XML文件中这么做是安全的,因为旧版本的Android系统会简单地忽略showAsAction属性(就是这样,你不需要用到res/menu-v11/中的单独版本文件)。
Use Platform Styles and Themes
Android提供了用户体验主题,为app提供可基础操作系统的外观和体验。通过manifest文件,这些主题可以被运行到我们的app中。通过使用内置的主题和样式,我们的app将随着系统的更新而自动匹配最新的外观和体验。
使你的activity看起来向对话框:
<activity android:theme="@android:style/Theme.Dialog">
使你的activity有一个透明的主题:
<activity android:theme="@android:style/Theme.Transucent">
应用在res/value/styles.xml定义的自定义主题:
<activity android:theme="@style/CustomTheme">
添加一个主题到整个app(所有的activity),在元素中添加android:theme主题:
<application android:theme="@style/CustomTheme">