前言
没啥说的,就是Android屏幕适配的笔记整理。
使用相对布局
LinearLayout却不允许你精准的控制它子view的关系,子view在LinearLayout中只能简单一个接一个的排成行。如果你需要你的子view不只是简简单单的排成行的排列,更好的方法是使用RelativeLayout,它允许你指定你布局中控件与控件之间的关系,
使用据尺寸限定词
布局文件放在加上类似large,sw600dp等这样限定词的文件夹中,以此来告诉系统根据屏幕选择对应的布局文件,比如下面例子的layout-large文件夹)
多应用都为大屏幕实现了“two-panes”模式(应用可能在一个方框中实现一个list,另外一个则实现list的content),平板和电视都是大到能在一个屏幕上适应两个方框,但是手机屏幕却只能单个显示。所以,如果你想实现这些布局,你就需要以下文件:
使用最小宽度限定词
老版Galaxy Tab和一般的7寸平板,有很多的应用都想针对这些不同的设备(比如5和7寸的设备)定义不同的布局,但是这些设备都被定义为了large尺寸屏幕。正是因为这个,所以Android在3.2的时候开始使用最小宽度限定词。最小宽度限定词允许你根据设备的最小宽度(dp单位)来指定不同布局。
这样意味着当你的设备的最小宽度等于600dp或者更大时,系统选择layout-sw600dp/main.xml(two_panes)的布局,而小一点的屏幕则会选择layout/main.xml(single_panes)的布局。 然而,在3.2之前还没有将sw600dp作为一个限定词出现,所以,你还是需要使用large限定词来做。 因此,你还是应该要有一个布局文件名为res/layout-large/main.xml,和res/layout-sw600dp/main.xml一样。
如何避免像这样出现重复的布局文件?
解决方案一
layout-sw600dp和layout-xlarge同时存在,建立不同的values文件夹的layout.xml
比如有一个布局要兼容大小屏幕,在Activity中引入的布局名字为activity_my_schedule:
在 res文件夹下创建不同的 values文件夹,来指向同一布局文件
res/values/layout.xml
1 2 3 | <resources> <item name="activity_my_schedule" type="layout">@layout/activity_my_schedule_wide</item> </resources> |
res/values-sw600dp\layout.xml
1 2 3 | <resources> <item name="activity_my_schedule" type="layout">@layout/activity_my_schedule_wide</item> </resources> |
另一种解决方案
你可以只使用一个layout布局文件,在 res文件夹下创建不同的 values文件夹,来指向不同的局文件。
我们来看Google开源项目Iosched中的实际应用,在layout下面有两个布局文件,分别用于适配大小屏幕:
res/layout/activity_my_schedule_wide
res/layout/activity_my_schedule_narrow
创建不同的values文件夹的layout,layout用于小屏幕,values-sw600dp-land用于横屏的情况:
res/values/layout.xml
1 2 3 | <resources> <item name="activity_my_schedule" type="layout">@layout/activity_my_schedule_narrow</item> </resources> |
res/values-sw600dp-land\layout.xml
1 2 3 | <resources> <item name="activity_my_schedule" type="layout">@layout/activity_my_schedule_wide</item> </resources> |
更复杂的需求,不同的情况选择不同的布局,只需要在res下面建立不同的values的layout,引用指定的布局名称即可,常见的values类型有:
res/values/layouts.xml:
res/values-sw600dp-land/layouts.xml:
res/values-sw600dp-port/layouts.xml:
res/values-xlarge-land/layouts.xml:
res/values-xlarge-port/layouts.xml:
使用点9图片
支持不同的屏幕尺寸同时也意味着你的图片资源也必须能兼容不同的屏幕尺寸。比如,一个button的背景图片就必须要适应该button的各种形状。
如果你在使用组件时可以改变图像的大小,你很快就会发现这是一个不明确的选择,因为运行的时候,图片会被拉伸或者压缩(这样容易造成图像失真)。
避免这种情况的解决方案就是使用点9图片,这是一种能够指定哪些区域能够或者不能够拉伸的特殊png文件。
兼容不同的屏幕密度
使用密度独立像素(dp)
不同的屏幕有不同的像素密度,所以,同样单位的像素在不同的设备上会有不同的物理尺寸。因此,在指定单位的时候,通常使用dp或者sp。
一个dp代表一个密度独立像素,也就相当于在每英寸160点的屏幕上,1dp = 1px。sp也是一个基本的单位,不过它主要是用在文本尺寸
上(它也是一种尺寸规格独立的像素),所以,你在定义文本尺寸的时候应该使用这种规格单位(不要使用在布尺寸上)。
为了提供更好的用户体验,你应该使用以下几种规格为不同的屏幕密度提供位图资源:
xhdpi:2.0
hdpi:1.5
mdpi:1.0(标准线)
ldpi:0.75
这也就意味着如果在xhdpi设备上你需要一个200x200的图片,那么你则需要一张150x150的图片用于hdpi,100x100的用于mdpi以及75x75的
用户ldpi设备。
实现可适应的UI流程
确定当前布局模式
当你在实现不同布局的时候,首先,你应该确定用户在当前的情况下看到的view应该是个什么样子。比如,你可能想知道当前用户到底是处于
“单个方框”的模式还是“多个方框”的模式。这个时候,你就可以通过查询指定的view是不是存在并是否显示来判断当前的模式:
1 2 3 | View articleView = findViewById(R.id.article); mIsDualPane = articleView != null && articleView.getVisibility() == View.VISIBLE; |
另一个关于如何适配已经存在的不同组件的例子是在组件执行操作之前先检查它是否是可用的。
根据当前布局模式响应
根据当前不同的布局有一些操作肯定会带来不一样的结果。你点击headlines列表中的某一条headline时,如果你的UI是在多个方框模式中,
内容会显示在右边的方框中,如果你的UI是在单个方框模式中,内容则会显示在一个新的独立的Activity中:
在其他Activity中复用Fragment
设计为多屏幕适配的UI时有一个复用的原则:
将你的界面变为单独部分,这样它能在某些屏幕配置上被实现为一个方框,而在其他屏幕配置中,则被实现为一个单独的activity。
当你在设计fragment的时候,有一个非常重要的知识点:
不要为某个特定的activity设计耦合度高的fragment。通常的做法是,通过定义抽象接口,并在接口中定义需要与该fragment进行交互的
activity的抽象方法,然后与该fragment进行交互的activity实现这些抽象接口方法的具体方法。在Fragment中定义需要与Activity交互
的接口,让Activity去实现它。
处理屏幕配置变化
如果使用的是单独的activity来实现你界面的不同部分,你需要注意的是,屏幕变化(如旋转变化)的时候,你也应该根据屏幕配置的变化来改变
你UI的变化。。
这也就意味着,当用户在竖屏模式下观看文章的时候,你需要检测屏幕是否被改变为了横屏,如果改变了,则结束当前activity并返回到主activity
中,这样,UI就能显示为两个方框的模式了。