对于多分辨率的适配,Android官方提供了一个说明文档,原文链接如下:
http://developer.android.com/training/multiscreen/index.html
对其做了一个翻译,方便日后参考学习。
支持不同大小的屏幕
一.使用“wrap_content”和“match_parent”
为了确保布局文件能够灵活的适应于不同大小的屏幕,对于一些视图的宽度和高度属性的值应该使用“wrap_content”和“match_content”。如果使用“wrap_content”,视图的高度和宽度将被设置为满足视图内容的最小值,而“match_parent”(在API 8之前也称为“fill_parent”)使得控件扩展来匹配其父控件的大小。
通过使用“wrap_content”和"match_parent"属性值替代具体的数字值,视图不但能够使用需要的空间,而且能够扩展到能够使用的空间,例如:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
<LinearLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
android:orientation=
"vertical"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
>
<LinearLayout android:layout_width=
"match_parent"
android:id=
"@+id/linearLayout1"
android:gravity=
"center"
android:layout_height=
"50dp"
>
<ImageView android:id=
"@+id/imageView1"
android:layout_height=
"wrap_content"
android:layout_width=
"wrap_content"
android:src=
"@drawable/logo"
android:paddingRight=
"30dp"
android:layout_gravity=
"left"
android:layout_weight=
"0"
/>
<View android:layout_height=
"wrap_content"
android:id=
"@+id/view1"
android:layout_width=
""
android:layout_weight=
"1"
/>
<Button android:id=
"@+id/categorybutton"
android:background=
"@drawable/button_bg"
android:layout_height=
"match_parent"
android:layout_weight=
"0"
android:layout_width=
"120dp"
style=
"@style/CategoryButtonStyle"
/>
</LinearLayout>
<fragment android:id=
"@+id/headlines"
android:layout_height=
"fill_parent"
android:name=
"com.example.android.newsreader.HeadlinesFragment"
android:layout_width=
"match_parent"
/>
</LinearLayout>
|
上面的例子中使用了”wrap_content“和”fill_parent“属性而不是具体的数字值。这使得布局能够正确的适应不同大小和方向的屏幕。
二.使用RelativeLayout
使用LinearLayout能够在一定程度上面构成复杂的布局。然而,LinearLayout不能使你精确构建子视图之间的空间关系。在LinearLayout中的视图通常都是简单排成队列。如果你想要视图能够适应不同的情况排列,而不是简单的线性布局,一个更好的选择就是使用RelativeLayout,这能够使你明确指定布局中视图的空间关系。例如,你可以排列一个子视图在另一个子视图的左边或者右边。
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
<?
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"
>
<
TextView
android:id
=
"@+id/label"
android:layout_width
=
"match_parent"
android:layout_height
=
"wrap_content"
android:text
=
"Type here:"
/>
<
EditText
android:id
=
"@+id/entry"
android:layout_width
=
"match_parent"
android:layout_height
=
"wrap_content"
android:layout_below
=
"@id/label"
/>
<
Button
android:id
=
"@+id/ok"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_below
=
"@id/entry"
android:layout_alignParentRight
=
"true"
android:layout_marginLeft
=
"10dp"
android:text
=
"OK"
/>
<
Button
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_toLeftOf
=
"@id/ok"
android:layout_alignTop
=
"@id/ok"
android:text
=
"Cancel"
/>
</
RelativeLayout
>
|
三.使用大小相关的布局修饰
上面一节中所述的内容能够通过拉伸视图空间来适应不同大小的屏幕,但不能够提供最好的用户体验。因此,应用不仅要实施灵活的布局,而且针对不同的屏幕配置要提供不同替代的布局文件。达到这个目的,你需要使用配置修饰,使得在运行时能够基于当前设备的配置自动选择最合适的的资源文件。(例如针对不同的屏幕大小设计不同的布局文件)
例如,很多应用程序对于大尺寸的屏幕施行”两个部分“的样式。平板电脑对于在屏幕上同时呈现两个部分是足够大的,但移动设备需要分别显示他们。为了实现这种布局,你需要有以下文件:
01
|
res/layout/main.xml, single-pane (default) layout:
|
01
02
03
04
05
06
07
08
09
10
|
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
android:orientation
=
"vertical"
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
>
<
fragment
android:id
=
"@+id/headlines"
android:layout_height
=
"fill_parent"
android:name
=
"com.example.android.newsreader.HeadlinesFragment"
android:layout_width
=
"match_parent"
/>
</
LinearLayout
>
|
01
|
res/layout-large/main.xml, two-pane layout:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
<LinearLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
android:layout_width=
"fill_parent"
android:layout_height=
"fill_parent"
android:orientation=
"horizontal"
>
<fragment android:id=
"@+id/headlines"
android:layout_height=
"fill_parent"
android:name=
"com.example.android.newsreader.HeadlinesFragment"
android:layout_width=
"400dp"
android:layout_marginRight=
"10dp"
/>
<fragment android:id=
"@+id/article"
android:layout_height=
"fill_parent"
android:name=
"com.example.android.newsreader.ArticleFragment"
android:layout_width=
"fill_parent"
/>
</LinearLayout>
|
注意在第二级目录中的”large“修饰符。在被定义为large的设备上面就会选择该布局文件。没有large修饰符的布局文件将会被更小的设备选择。
四.使用Smallest-width修饰符
很多应用程序都想要为属于”large“这一范围的不同设备展示不同的布局(例如5寸和7寸的设备)。因此Android从3.2开始引入了”Smallest-width“修饰符。
”Smallest-width“修饰符允许你把最小宽度为width的屏幕作为目标(单位dp)。例如,典型的7寸平板有最小宽度为600dp,因此如果你希望你的界面在这些设备上面展示两个部分,你可以使用这种修饰符。
01
|
res/layout/main.xml, single-pane (default) layout:
|
01
02
03
04
05
06
07
08
09
10
|
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
android:orientation
=
"vertical"
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
>
<
fragment
android:id
=
"@+id/headlines"
android:layout_height
=
"fill_parent"
android:name
=
"com.example.android.newsreader.HeadlinesFragment"
android:layout_width
=
"match_parent"
/>
</
LinearLayout
>
|
01
|
res/layout-sw600dp/main.xml, two-pane layout:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
<LinearLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
android:layout_width=
"fill_parent"
android:layout_height=
"fill_parent"
android:orientation=
"horizontal"
>
<fragment android:id=
"@+id/headlines"
android:layout_height=
"fill_parent"
android:name=
"com.example.android.newsreader.HeadlinesFragment"
android:layout_width=
"400dp"
android:layout_marginRight=
"10dp"
/>
<fragment android:id=
"@+id/article"
android:layout_height=
"fill_parent"
android:name=
"com.example.android.newsreader.ArticleFragment"
android:layout_width=
"fill_parent"
/>
</LinearLayout>
|
上面的布局意味着宽度高于或等于600dp的设备将会选择layout-sw600dp/main.xml中的布局,而小尺寸的设备将会选择layout/main.xml中的布局。
然而,这种方式在3.2之前的设备上面是无法工作的,因为它们不识别sw600dp的标示符,所以你同时也要使用large标示符。因此,你需要一个res/layout-large/main.xml的文件,而他的内容与res/layout-sw600dp/main.xml的文件相同。
五.使用Layout修饰符需要注意的问题
”smallest-width“修饰符只有在3.2以上的设备才能被使用。因此,你仍然需要使用抽象的尺寸分类(small、normal、large、xlarge)来与之前的设备兼容。例如,如果你想要设计UI,在移动设备上面显示一个部分,而在7寸设备上面同时显示多个部分,你需要提供下面这些资源:
01
02
03
|
res/layout/main.xml: single-pane layout
res/layout-large: multi-pane layout
res/layout-sw600dp: multi-pane layout
|
最后的两个文件是相同的,因为其中一个将会被3.2以上的设备匹配,而另外一个将会为之前版本的平板带来好处。
为了避免对相同文件的复制,可以使用别名文件,例如,你可以定义如下的布局:
01
02
|
res/layout/main.xml, single-pane layout
res/layout/main_twopanes.xml, two-pane layout
|
同时添加如下两个文件:
01
|
res/values-large/layout.xml:
|
01
02
03
|
<
resources
>
<
item
name
=
"main"
type
=
"layout"
>@layout/main_twopanes</
item
>
</
resources
>
|
01
|
res/values-sw600dp/layout.xml:
|
01
02
03
|
<
resources
>
<
item
name
=
"main"
type
=
"layout"
>@layout/main_twopanes</
item
>
</
resources
>
|
后面的两个文件具有相同的内容,但他们并没有真实定义布局,他们仅仅建立了一个main_twopanes的别名。
六.使用方向修饰符
一些布局在横向和纵向都能够很好的工作,但根据不同的情况进行调整总是有益的。如下面的例子:
01
02
03
04
05
06
07
|
small screen, portrait: single pane, with logo
small screen, landscape: single pane, with logo
7" tablet, portrait: single pane, with action bar
7" tablet, landscape: dual pane, wide, with action bar
10" tablet, portrait: dual pane, narrow, with action bar
10" tablet, landscape: dual pane, wide, with action bar
TV, landscape: dual pane, wide, with action bar
|
这些中的每一个都应该在res/layout/目录中定义。然后为不同的屏幕配置适配不同的布局文件。
01
|
res/layout/onepane.xml:
|
01
02
03
04
05
06
07
08
09
10
|
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
android:orientation
=
"vertical"
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
>
<
fragment
android:id
=
"@+id/headlines"
android:layout_height
=
"fill_parent"
android:name
=
"com.example.android.newsreader.HeadlinesFragment"
android:layout_width
=
"match_parent"
/>
</
LinearLayout
>
|
01
|
res/layout/onepane_with_bar.xml:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
android:orientation
=
"vertical"
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
>
<
LinearLayout
android:layout_width
=
"match_parent"
android:id
=
"@+id/linearLayout1"
android:gravity
=
"center"
android:layout_height
=
"50dp"
>
<
ImageView
android:id
=
"@+id/imageView1"
android:layout_height
=
"wrap_content"
android:layout_width
=
"wrap_content"
android:src
=
"@drawable/logo"
android:paddingRight
=
"30dp"
android:layout_gravity
=
"left"
android:layout_weight
=
"0"
/>
<
View
android:layout_height
=
"wrap_content"
android:id
=
"@+id/view1"
android:layout_width
=
"wrap_content"
android:layout_weight
=
"1"
/>
<
Button
android:id
=
"@+id/categorybutton"
android:background
=
"@drawable/button_bg"
android:layout_height
=
"match_parent"
android:layout_weight
=
"0"
android:layout_width
=
"120dp"
style
=
"@style/CategoryButtonStyle"
/>
</
LinearLayout
>
<
fragment
android:id
=
"@+id/headlines"
android:layout_height
=
"fill_parent"
android:name
=
"com.example.android.newsreader.HeadlinesFragment"
android:layout_width
=
"match_parent"
/>
</
LinearLayout
>
|
01
|
res/layout/twopanes.xml:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
android:orientation
=
"horizontal"
>
<
fragment
android:id
=
"@+id/headlines"
android:layout_height
=
"fill_parent"
android:name
=
"com.example.android.newsreader.HeadlinesFragment"
android:layout_width
=
"400dp"
android:layout_marginRight
=
"10dp"
/>
<
fragment
android:id
=
"@+id/article"
android:layout_height
=
"fill_parent"
android:name
=
"com.example.android.newsreader.ArticleFragment"
android:layout_width
=
"fill_parent"
/>
</
LinearLayout
>
|
01
|
res/layout/twopanes_narrow.xml:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
android:orientation
=
"horizontal"
>
<
fragment
android:id
=
"@+id/headlines"
android:layout_height
=
"fill_parent"
android:name
=
"com.example.android.newsreader.HeadlinesFragment"
android:layout_width
=
"200dp"
android:layout_marginRight
=
"10dp"
/>
<
fragment
android:id
=
"@+id/article"
android:layout_height
=
"fill_parent"
android:name
=
"com.example.android.newsreader.ArticleFragment"
android:layout_width
=
"fill_parent"
/>
</
LinearLayout
>
|
既然所有的布局都已经被定义,目前的问题就是为不同的配置选择正确的布局文件。
01
|
res/values/layouts.xml:
|
01
02
03
04
|
<
resources
>
<
item
name
=
"main_layout"
type
=
"layout"
>@layout/onepane_with_bar</
item
>
<
bool
name
=
"has_two_panes"
>false</
bool
>
</
resources
>
|
01
|
res/values-sw600dp-land/layouts.xml:
|
01
02
03
04
|
<
resources
>
<
item
name
=
"main_layout"
type
=
"layout"
>@layout/twopanes</
item
>
<
bool
name
=
"has_two_panes"
>true</
bool
>
</
resources
>
|
01
|
res/values-sw600dp-port/layouts.xml:
|
01
02
03
04
|
<
resources
>
<
item
name
=
"main_layout"
type
=
"layout"
>@layout/onepane</
item
>
<
bool
name
=
"has_two_panes"
>false</
bool
>
</
resources
>
|
01
|
res/values-large-land/layouts.xml:
|
01
02
03
04
|
<
resources
>
<
item
name
=
"main_layout"
type
=
"layout"
>@layout/twopanes</
item
>
<
bool
name
=
"has_two_panes"
>true</
bool
>
</
resources
>
|
01
|
res/values-large-port/layouts.xml:
|
01
02
03
04
|
<
resources
>
<
item
name
=
"main_layout"
type
=
"layout"
>@layout/twopanes_narrow</
item
>
<
bool
name
=
"has_two_panes"
>true</
bool
>
</
resources
>
|
01
02
03
04
|
<
Button
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"@string/clickme"
android:layout_marginTop
=
"20dp"
/>
|
01
02
03
|
<
TextView
android:layout_width
=
"match_parent"
android:layout_height
=
"wrap_content"
android:textSize
=
"20sp"
/>
|
01
02
03
04
|
xhdpi: 2.0
hdpi: 1.5
mdpi: 1.0 (baseline)
ldpi: 0.75
|
01
02
03
04
05
06
07
08
09
10
|
MyProject/
res/
drawable-xhdpi/
awesomeimage.png
drawable-hdpi/
awesomeimage.png
drawable-mdpi/
awesomeimage.png
drawable-ldpi/
awesomeimage.png
|