支持各种尺寸的屏幕
支持各种尺寸的屏幕课程内容
该课程将告诉您如何通过如下方式来支持各种尺寸的屏幕:
要确保您的布局是弹性的并且可以适应各种尺寸的屏幕,你应该使用"wrap_content"
和"match_parent"
来设置一些控件的宽高。如果使用"wrap_content"
,控件的宽度和高度将会设置为能够显示该控件内容的最小尺寸;而当你使用"match_parent"
(在API level 8之前被称之为"fill_parent"
)的时候,控件的高度和宽度将和父控件的大小一样。
当使用"wrap_content"
<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>?
注意示例中的代码是如何使用
新闻阅读程序在横向(左)和纵向(右)的显示
使用 RelativeLayout通过"wrap_content"
<?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>?
下图显示了该布局在QVGA屏幕上的界面
在QVGA屏幕上的截图(小屏幕)
在大屏幕上的界面
在WSVGA屏幕上的截图(大屏幕)
注意:尽管控件的大小改变了, 但是他们之间的相对位置通过RelativeLayout.LayoutParams
定义为一样。
您可以通过前面的方法实现各种各样的自适应布局和相对布局。但是这种布局只是通过把控件拉伸或者拉伸控件周围的空间,对于大小不同的屏幕并没有提供最优的用户体验。因此,您的程序应该不仅仅只是实现自适应的布局,还应该根据不同的屏幕配置分别提供更加友好的布局。通过配置限定符可以实现这个优化,这样在运行时系统会自动的选择适合当前设备的布局和资源(例如:针对不同屏幕使用不同的布局)。
例如,很多程序在大屏幕设备上使用“两个窗口”布局模式(程序可以在一个窗口中显示一个列表而在另外一个窗口中显示列表中选中的内容)。平板设备和电视剧的屏幕足够用来同时显示两个窗口,但是手机设备就只能分别显示他们了。因此,要实现这种布局,您需要使用如下的文件:
res/layout/main.xml
, 单个窗口(默认)布局<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>?
res/layout-xlarge/main.xml
, 两个窗口布局<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>?
注意上面的文件夹中的xlarge
限定符,这个文件夹里面的布局只会用到屏幕尺寸为超级大(例如:10寸的平板)的设备中。其他的布局(没有限定符的)将会用于小屏幕的设备中。
在Android 3.2之前的版本上,开发者可能有点郁闷,应为之前的“large”限定符包含的尺寸太宽泛了,例如 Dell Streak、Galaxy 平板、以及7寸的平板。但是很多开发者都想在这个范围内根据不同的具体屏幕尺寸来显示不同的布局(例如 5寸和7寸的设备)。在Android 3.2版本中引入 “Smallest-width”限定符就是为了解决这个问题的。
Smallest-width限定符可以让你指定目标设备的最少屏幕尺寸(单位是dp)。例如,普通的7寸平板的最小宽度是600dp,因此如果你希望你的程序在这种尺寸的屏幕上使用两个窗口(小于该尺寸的屏幕使用一个窗口),那么您可以使用上面的两个布局文件,只要把xlarge
限定符替换为sw600dp
即可, 可以看出在3.2+版本中,对屏幕的限定更加详细了。
res/layout/main.xml
, 一个窗口(默认)布局<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>?
res/layout-sw600dp/main.xml
, 两个窗口布局<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
这个限定符,这样您还是要同时使用xlarge
限定符。这样您的res/layout-xlarge/main.xml
<resources> <item name="main" type="layout">@layout/main_twopanes</item></resources>?
res/values-sw600dp/layout.xml
<resources> <item name="main" type="layout">@layout/main_twopanes</item></resources>?
main
为main_twopanes
的一个别名。既然该布局文件有xlarge
<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>?res/layout/onepane_with_bar.xml
<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>?
res/layout/twopanes.xml
<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>?
res/layout/twopanes_narrow.xml
:
现在所有的布局文件都定义好了,只要使用配置限定符做好影射即可,通过布局别名很容易实现:
res/values/layouts.xm
<resources> <item name="main_layout" type="layout">@layout/onepane_with_bar</item> <bool name="has_two_panes">false</bool></resources>?
res/values-sw600dp-land/layouts.xml
<resources> <item name="main_layout" type="layout">@layout/twopanes</item> <bool name="has_two_panes">true</bool></resources>?
res/values-sw600dp-port/layouts.xml
<resources> <item name="main_layout" type="layout">@layout/onepane</item> <bool name="has_two_panes">false</bool></resources>?
res/values-xlarge-land/layouts.xml
<resources> <item name="main_layout" type="layout">@layout/twopanes</item> <bool name="has_two_panes">true</bool></resources>?
res/values-xlarge-port/layouts.xml
<resources> <item name="main_layout" type="layout">@layout/twopanes_narrow</item> <bool name="has_two_panes">true</bool></resources>?
使用Nine-patch格式图片
支持不同尺寸的屏幕也意味着在不同的屏幕上使用不同大小的图片。例如,一个按钮的背景图片在任何尺寸的按钮上都应该是差不多的。
如果您在能改变大小的控件上使用同一个图片,你将会发现这些图片将会被缩放,看起来有点毛毛糙糙。而Android系统中的nine-patch格式图片就解决了这个问题。
要让一个普通的图片转换为nine-patch格式的,如下图(为了清楚的演示,该图被放大了4倍)
button
通过Android SDK中的
button.9.png
注意 边框上的黑色像素点。左边和上边的黑点定义了图片可以被拉伸的地方,右边和下边的黑点定义了控件内容可以显示的地方。
同时也要注意图片的扩展名为.9.png
。只有这种格式的图片系统才认为是nine-patch格式的。
如果您使用该图片作为控件的背景(代码android:background="@drawable/button"
),系统会自动的拉伸响应的地方,如下图所示:
button.9.png 在各种尺寸下被拉伸的情况