本文将告诉你如何让你的应用程序支持各种不同屏幕大小,主要通过以下几种办法:
- 让你的布局能充分的自适应屏幕
- 根据屏幕的配置来加载合适的UI布局
- 确保正确的布局应用在正确的设备屏幕上
- 提供可以根据屏幕大小自动伸缩的图片
使用 "wrap_content" 和 "match_parent"
为了确保你的布局能够自适应各种不同屏幕大小,你应该在布局的视图中使用"wrap_content"和"match_parent"来确定它的宽和高。如果你使用了"wrap_content",相应视图的宽和高就会被设定成刚好能够包含视图中内容的最小值。而如果你使用了"match_parent"(在Android API 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
通过多层嵌套LinearLayout和组合使用"wrap_content"和"match_parent"已经可以构建出足够复杂的布局。但是LinearLayout无法允许你准确地控制子视图之前的位置关系,所有LinearLayout中的子视图只能简单的一个挨着一个地排列。如果你需要让子视图能够有更多的排列方式,而不是简单地排成一行或一列,使用RelativeLayout将会是更好的解决方案。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屏幕上显示的结果。
下图展示了这个布局在一个更大的屏幕上显示的结果。
可以注意到,即使屏幕的大小改变,视图之前的相对位置都没有改变。
使用Size限定符
虽然使用以上几种方式可以解决屏幕适配性的问题,但是那些通过伸缩控件来适应各种不同屏幕大小的布局,未必就是提供了最好的用户体验。你的应用程序应该不仅仅实现了可自适应的布局,还应该提供一些方案根据屏幕的配置来加载不同的布局,可以通过配置限定符(configuration qualifiers)来实现。配置限定符允许程序在运行时根据当前设备的配置自动加载合适的资源(比如为不同尺寸屏幕设计不同的布局)。
现在有很多的应用程序为了支持大屏设备,都会实现“two pane”模式(程序会在左侧的面板上展示一个包含子项的List,在右侧面板上展示内容)。平板和电视设备的屏幕都很大,足够同时显示两个面板,而手机屏幕一次只能显示一个面板,两个面板需要分开显示。所以,为了实现这种布局,你可能需要以下文件:
res/layout/main.xml,single-pane(默认)布局:
- <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-large/main.xml,two-pane布局:
- <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限定符,那些被定义为大屏的设备(比如7寸以上的平板)会自动加载此布局,而小屏设备会加载另一个默认的布局。
使用Smallest-width限定符
使用Size限定符有一个问题会让很多程序员感到头疼,large到底是指多大呢?很多应用程序都希望能够更自由地为不同屏幕设备加载不同的布局,不管它们是不是被系统认定为"large"。这就是Android为什么在3.2以后引入了"Smallest-width"限定符。
Smallest-width限定符允许你设定一个具体的最小值(以dp为单位)来指定屏幕。例如,7寸的平板最小宽度是600dp,所以如果你想让你的UI在这种屏幕上显示two pane,在更小的屏幕上显示single pane,你可以使用sw600dp来表示你想在600dp以上宽度的屏幕上使用two pane模式。
res/layout/main.xml,single-pane(默认)布局:
- <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,two-pane布局:
- <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(two-pane)布局,而更小屏幕的设备将会选择layout/main.xml(single-pane)布局。
然而,使用早于Android 3.2系统的设备将无法识别sw600dp这个限定符,所以你还是同时需要使用large限定符。这样你就需要在res/layout-large和res/layout-sw600dp目录下都添加一个相同的main.xml。下节你将会看到如何避免重复定义这种布局的技巧。
使用布局别名
Smallest-width限定符仅在Android 3.2及之后的系统中有效。因而,你也需要同时使用Size限定符(small, normal, large和xlarge)来兼容更早的系统。例如,你想手机上显示single-pane界面,而在7寸平板和更大屏的设备上显示multi-pane界面,你需要提供以下文件:
- res/layout/main.xml: single-pane布局
- res/layout-large: multi-pane布局
- res/layout-sw600dp: multi-pane布局
最后的两个文件是完全相同的,为了要解决这种重复,你需要使用别名技巧。例如,你可以定义以下布局:
- res/layout/main.xml, single-pane布局
- res/layout/main_twopanes.xml, two-pane布局
加入以下两个文件:
res/values-large/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。这样两个layout.xml都只是引用了@layout/main_twopanes,就避免了重复定义布局文件的情况。
使用Orientation限定符
有些布局会在横屏和竖屏的情况下都显示的很好,但是多数情况下这些布局都可以再调整的。在News Reader示例程序中,布局在不同屏幕尺寸和不同屏幕方向中是这样显示的:
- 小屏幕, 竖屏: 单面板, 显示logo
- 小屏幕, 横屏: 单面板, 显示logo
- 7寸平板, 竖屏: 单面板, 显示action bar
- 7寸平板, 横屏: 双面板, 宽, 显示action bar
- 10寸平板, 竖屏: 双面板, 窄, 显示action bar
- 10寸平板, 横屏: 双面板, 宽, 显示action bar
- 电视, 横屏: 双面板, 宽, 显示action bar
所有这些布局都是定义在 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:
- <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>
现在所有需要的布局都已经定义好了,剩下的只要使用限定符来让各个设备根据屏幕配置加载正确的布局了。你现在就可以使用布局别名技术:
res/values/layouts.xml:
- <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-large-land/layouts.xml:
- <resources>
- <item name="main_layout" type="layout">@layout/twopanes</item>
- <bool name="has_two_panes">true</bool>
- </resources>
res/values-large-port/layouts.xml:
- <resources>
- <item name="main_layout" type="layout">@layout/twopanes_narrow</item>
- <bool name="has_two_panes">true</bool>
- </resources>
使用Nine-Patch图片
支持不同屏幕大小通常情况下也意味着,你的图片资源也需要有自适应的能力。例如,一个按钮的背景图片必须能够随着按钮大小的改变而改变。
如果你想使用普通的图片来实现上述功能,你很快就会发现结果是令人失望的,因为运行时会均匀地拉伸或压缩你的图片。解决方案是使用nine-patch图片,它是一种被特殊处理过的PNG图片,你可以指定哪些区域可以拉伸而哪些区域不可以。
因而,当你设计需要在不同大小的控件中使用的图片时,最好的方法就是用nine-patch图片。为了将图片转换成nine-patch图片,你可以从一张普通的图片开始:
然后通过SDK中带有的draw9patch工具打开这张图片(工具位置在SDK的tools目录下),你可以在图片的左边框和上边框绘制来标记哪些区域可以被拉伸。你也可以在图片的右边框和下边框绘制来标记内容需要放置在哪个区域。结果如下图所示:
注意图片边框上的黑色像素,在上边框和左边框的部分表示当图片需要拉伸时就拉伸黑点标记的位置。在下边框和右边框的部分表示内容将会被放置的区域。
同时需要注意,这张图片的后缀名是 .9.png。你必须要使用这个后缀名,因为系统就是根据这个来区别nine-patch图片和普通的PNG图片的。
当你需要在一个控件中使用nine-patch图片时(如android:background="@drawable/button"),系统就会根据控件的大小自动地拉伸你想要拉伸的部分,效果如下图所示:
相关推荐
在Android系统中,屏幕大小和精度是两个关键的硬件特性,它们直接影响了用户界面的显示效果和应用的兼容性。本文将深入探讨Android设备的多分辨率支持、相关的术语与概念,以及支持的屏幕分辨率范围。 一、多分辨率...
在Android应用开发中,确保应用程序能够自适应各种手机屏幕大小和分辨率是至关重要的。这不仅可以提供优秀的用户体验,也是Google Play商店对应用质量的基本要求。以下是一些关键知识点,帮助开发者实现这一目标: ...
Google推出的Material Design设计规范为Android开发提供了统一的视觉语言,包括对不同屏幕尺寸的适配建议,遵循这些指南可以帮助创建跨平台一致性体验。 综上所述,Android屏幕适配是一个多维度、系统性的工程,...
### Android自适应屏幕大小与Layout布局详解 #### 一、不同屏幕尺寸的适应性设计 在Android应用开发中,为了确保应用能够在各种不同尺寸的屏幕上正常显示,开发者需要考虑多种屏幕分辨率的情况。例如,常见的屏幕...
在Android开发中,确保应用程序能够适应不同屏幕大小是至关重要的,因为Android设备有着广泛的屏幕尺寸和分辨率。本文将深入探讨几种关键方法,帮助开发者创建能够跨多种设备自适应的UI。 首先,要实现布局的自适应...
AutoLayout-Android, 支持多个屏幕的简单方法 面向Android的自动布局支持多个屏幕的简单方法。自动调整大小:每次使用屏幕尺寸时,写入。。自定义自适应策略。支持的纵横比。这里项目是来自 hongyangandroid/android...
本文将深入探讨如何使用官方推荐的方法,通过自动生成不同版本的`dimens.xml`文件来实现屏幕适配。 首先,我们需要理解Android系统如何处理屏幕尺寸和密度。Android设备有多种屏幕类型,包括small、normal、large、...
- Android支持多种资源目录,如`res/layout-mdpi`, `res/layout-xhdpi`等,用于存放针对不同密度的布局文件。 - 同样,可以创建`res/drawable-mdpi`, `res/drawable-xhdpi`等目录,存储不同分辨率的图片资源。 3....
Android支持多屏幕机制即用为当前设备屏幕提供一种合适的方式来共同管理并解析应用资源。本文就介绍了4中Android屏幕自适应解决方案。 一、细说layout_weight 目前最为推荐的Android多屏幕自适应解决方案。 该...
5. **使用约束布局(ConstraintLayout)**:Android Studio提供的约束布局可以灵活地进行响应式设计,适应不同屏幕尺寸。 6. **使用布局权重(layout_weight)**:在LinearLayout中,分配权重可以使得子视图按照...
9. **兼容模式**:Android的屏幕兼容性模式允许旧的应用程序在高分辨率设备上运行,尽管可能不那么理想,但能保证基本功能。 10. **Material Design指导**:遵循谷歌的Material Design规范,它提供了跨平台的布局和...
Android支持在不同的资源目录下存放特定屏幕尺寸和密度的资源文件。例如,`res/layout-sw600dp`用于7英寸平板,`res/drawable-mdpi`用于中等密度的设备。在"HelloWord"项目中,可能会有多个布局文件夹,每个对应一...
在Android系统中,由于设备的多样性,同一张图片在不同分辨率的屏幕上显示时,为了保持清晰度和视觉效果,往往需要有不同的尺寸版本。这涉及到Android的资源适配机制,包括密度独立像素(DP, Density Independent ...
Google提供的PercentSupport库使得开发者可以基于父视图的百分比来定义布局的大小,这样就能更好地适应不同屏幕尺寸。 5. **AutoFitTextView和自适应字体大小** 对于需要自适应字体大小的情况,可以使用开源库...
在Android应用开发中,屏幕适配是一个至关重要的环节,因为Android设备有着各种不同的屏幕尺寸和分辨率。`dimens.xml`文件是Android系统提供的一种资源文件,用于存储尺寸相关的常量,如字体大小、间距、控件尺寸等...
- **适配器(Adapter)**:如果涉及到列表或网格,适配器可能会有处理不同屏幕尺寸的方法,如`getView()`中根据屏幕大小调整视图大小。 - **比例计算**:代码可能包含计算屏幕比例的函数,用于确定控件的大小或...
在Android开发中,让应用程序能够自动适应不同尺寸和分辨率的屏幕是一项重要的任务。"Android自动适应屏幕源码"就是这样一个项目,它展示了如何通过编程技术实现应用在多种设备上显示时的良好布局和视觉效果。这个...
"android市场普遍的屏幕大小适配"这一主题聚焦于如何确保应用程序在不同设备上提供一致且良好的用户体验。 Android系统采用了一套灵活的资源目录结构来实现屏幕适配。这些资源目录通常位于项目的`res`文件夹下,并...
- 对于图像资源,遵循Android的密度独立像素(dp)规则,并提供不同密度的资源。 - 使用`dimen.xml`文件存储尺寸常量,便于在不同屏幕尺寸上进行调整。 - 利用`@dimen`引用在XML布局中设置尺寸,以方便统一管理。...
Android支持在不同的资源目录下存放特定密度的图片和其他资源。例如,hdpi、xhdpi、xxhdpi和xxxhdpi目录分别对应高、超高、极高和超极高密度设备。系统会自动选择最合适的资源。确保每个目录下的资源按比例缩放,以...