支持各种尺寸的屏幕
支持各种尺寸的屏幕
课程内容
- 使用”wrap_content”和”match_parent”
- 使用RelativeLayout
- 使用尺寸限定符
- 使用Smallest-width限定符
- 使用Layout别名
- 使用方向限定符
- 使用Nine-patch格式图片
您还应该阅读
动手试试
NewsReader.zip
该课程将告诉您如何通过如下方式来支持各种尺寸的屏幕:
- 确保您的布局可以改变大小来填充整个屏幕
- 根据屏幕的配置来显示不同的布局
- 确保布局应用到对应的屏幕上
- 使用能正确缩放的图片
使用”wrap_content”和”match_parent”
要确保您的布局是弹性的并且可以适应各种尺寸的屏幕,你应该使用"wrap_content"
和"match_parent"
来设置一些控件的宽高。如果使用"wrap_content"
,控件的宽度和高度将会设置为能够显示该控件内容的最小尺寸;而当你使用"match_parent"
(在API level 8之前被称之为"fill_parent"
)的时候,控件的高度和宽度将和父控件的大小一样。
当使用"wrap_content"
和
"match_parent"
来代替具体的大小数字的时候,您的控件要么只使用能显示其内容的最小尺寸或者填充整个能用的空间。下面是一个示例:
<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>
注意示例中的代码是如何使用
"wrap_content"
和
"match_parent"
而不是使用具体的数值来指定控件的大小。这样布局就可以根据不同的屏幕尺寸和方向来自适应显示界面。
下图是该布局在横向或者纵向的情况下的显示情况,注意 控件的宽度和高度自动的适应屏幕的尺寸:
使用 RelativeLayout
通过"wrap_content"
和
"match_parent"
以及嵌套使用多个LinearLayout
您可以实现各种复杂的布局。然而,LinearLayout
不允许精确的控制子控件之间的关系;在LinearLayout
里面的控件只是一个挨着一个去布局的。如果您不想让控件只是排成一行或者一列,使用
RelativeLayout
是一个更好的选择,该布局可以指定子控件之间的相对位置。例如,你可以指定一个子控件位于屏幕的左边而另外一个位于屏幕的右边。
示例
<?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屏幕上的界面
在大屏幕上的界面
注意:尽管控件的大小改变了, 但是他们之间的相对位置通过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寸的平板)的设备中。其他的布局(没有限定符的)将会用于小屏幕的设备中。
使用 Smallest-width 限定符
在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
文件和res/layout-sw600dp/main.xml
文件的内容是一样的。在下一个小节中,您会看到一种技术可以让你避免这种内容一样的布局文件出现。
使用布局别名
上面看到的Smallest-width限定符只适用于3.2+的设备,因此您还需要同时使用(small, normal,large and xlarge)这些限定符来让您的程序运行在3.2之前的系统中。例如:如果你想设计一个界面,在手机中显示一个窗口,而在7寸平板或者更大的设备中显示两个窗口,您需要这些布局文件:
-
res/layout/main.xml:
单个窗口布局 -
res/layout-xlarge:
两个窗口布局 -
res/layout-sw600dp:
两个窗口布局
后面的两个布局文件是一样的,一个是用于3.2+设备的;一个用于之前的设备的。
为了避免这种布局文件的重复,并且维护起来也很麻烦,您可以使用别名文件。例如您可以定义如下的布局文件:
-
res/layout/main.xml
, 单个窗口布局 -
res/layout/main_twopanes.xml
, 两个窗口布局
布局文件内容:
-
res/values-xlarge/layout.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
和sw600dp
这两个限定符,这样不管系统的版本是3.2之前的还是之后的,满足尺寸要求的都会使用该布局。
使用方向限定符
有些布局在横向和纵向屏幕中都表现很好,但是有些可以稍作修改从而提升用户体验。在新闻阅读示例程序中,下面展示了在不同的屏幕尺寸和屏幕方向中使用的布局:
- 小屏幕 纵向: 带Logo的单个窗口
- 小屏幕 横向: 带Logo的单个窗口
- 7寸平板, 纵向: 有动作条的单个窗口
- 7寸平板, 横向: 有动作条的两个宽窗口
- 10寸平板, 纵向: 有动作条的两个窄窗口
- 10寸平板, 横向: 有动作条的两个宽窗口
每个布局都在res/layout/
目录中定义了一个布局文件。通过布局别名来影射的不同的配置项中的:
res/layout/onepane.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/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倍)
通过Android SDK中的
draw9patch
工具(在tools/
目录中)编辑,详情请参考这篇详细介绍
,如下图:
注意 边框上的黑色像素点。左边和上边的黑点定义了图片可以被拉伸的地方,右边和下边的黑点定义了控件内容可以显示的地方。
同时也要注意图片的扩展名为.9.png
。只有这种格式的图片系统才认为是nine-patch格式的。
如果您使用该图片作为控件的背景(代码android:background="@drawable/button"
),系统会自动的拉伸响应的地方,如下图所示:
推荐阅读
-
android计算pad或手机的分辨率/像素/密度/屏幕尺寸/DPI值的方法
-
js获取浏览器和屏幕的各种宽度高度
-
MAC中用Shell脚本批量裁剪各种尺寸的App图标
-
android使用service和activity获取屏幕尺寸的方法
-
js获取浏览器和屏幕的各种宽度高度
-
2999以内唯一支持屏幕指纹的骁龙888旗舰!realme GT预热
-
ipad air2尺寸多大?苹果平板电脑ipad air2的屏幕大小介绍
-
MAC中用Shell脚本批量裁剪各种尺寸的App图标
-
屏幕最小的骁龙888旗舰!华硕ZenFone 8系列支持120Hz高刷新率
-
android 用java写一个自动适配各种屏幕大小的工具