版权声明:本文为博主原创文章(部分引用他人博文,已加上引用说明),未经博主允许不得转载。https://cloud.tencent.com/developer/article/1326629
转载请标明出处:
https://cloud.tencent.com/developer/article/1326629
本文出自 AWeiLoveAndroid的博客
Android适配是一个老生常谈的问题,很多程序员觉得很恶心,不愿意做适配,但是又不得不做。然后老板说,这位兄弟,做好了,今天晚饭给你加个鸡腿,然后程序员开始找各种资料,忙活起来了,最终在苦逼的煎熬中做完了。
好了,言归正传,根据多年开发经验,总结一下Android适配主要表现在以下 3个方面:
1、屏幕适配。(网上讲的最多的就是这个。) 由于Android碎片化严重,导致开发中一套代码在不同手机上运行起来效果不是很好,兼容性不是很好,这就需要对不同分辨率,不同屏幕大小的手机做屏幕适配。 2、版本适配。 不同的系统版本api有所变更,既要适配高版本,也要做到兼容低版本。 具体讲解请看链接: http://www.jianshu.com/p/49fa8ebc0105 3、ROM适配。(这个是最难的,工作量也是最大的,如果没有不同版本手机适配的积累,遇到问题都不知道怎么解决。) 由于Android是开源的,不同的手机厂商有自己定制的ROM,对系统的api可能有变更,也有可能新增一些api,所以在开发中,要针对不同厂商的手机做一些特殊适配。 具体讲解请看链接: http://www.jianshu.com/p/f9c67a4b908e
废话少说,开始进入正题。这篇文章我们先讲解第一个问题 ---- 屏幕适配。
程序猿把设计狮制作的效果图应用到不同的手机,对不同的屏幕进行界面调整的过程,确保界面不变形,呈现效果图的位置、尺寸、比例。
(1)屏幕物理尺寸:
屏幕对角线的尺寸。单位是英寸,1英寸 ≈ 2.54厘米
比如常见的屏幕尺寸有5.0、5.1、5.2、5.5、5.7、5.9、6.0等
(2)屏幕分辨率:
屏幕分辨率 = 横向像素*纵向像素(或者 宽x高),如 1080*1920
720x1280、1080x1920(当然还有480x800,这个很少见了)
(3)屏幕像素密度(dots per inch)
密度类型 | 代表的分辨率(px) | 屏幕像素密度(dpi) |
---|---|---|
低密度(ldpi) | 240x320 | 120 |
中密度(mdpi) | 320x480 | 160 |
高密度(hdpi) | 480x800 | 240 |
超高密度(xhdpi) | 720x1280 | 320 |
超超高密度(xxhdpi) | 1080x1920 | 480 |
(4)以上三者(屏幕尺寸、分辨率、像素密度)之间的关系
屏幕尺寸、分辨率、像素密度之间的换算图
(5)密度无关像素(dp 或 dip)
(6)独立比例像素(sp)
下面给一个实例说明,让你更能明白这几个单位:
看下图你可以知道:为什么使用了dp作为单位,两个手机分辨率也是一样的,可是按钮显示的宽度还是不一样?
总结一下,主要有以下两点:
首先看一张图:
屏幕适配 具体实现方式
4.1.1.布局适配
解决方案:使用相对布局(RelativeLayout),禁用绝对布局(AbsoluteLayout)。这个很基础,就不多说了。
解决方案:使用限定符。通过配置限定符使得程序在运行时根据当前设备的配置(屏幕尺寸)自动加载合适的布局资源。
限定符分类:
(1)尺寸(size)限定符(这种方式只适合Android 3.2版本之前
)
res目录新建一个layout-large文件夹,布局名字和res/layout里面的同名。在平板电脑和电视的屏幕(>7英寸)上:实施 双面板
模式以同时显示更多内容,它会加载res/layout-large里面的布局,在手机较小的屏幕上:使用 单面板
分别显示内容,加载的是res/layout里面的同名布局。
尺寸(size)限定符
(2)最小宽度(Smallest-width)限定符。
通过指定某个最小宽度(以 dp 为单位)来精确定位屏幕从而加载不同的UI资源。(适用于Android 3.2及之后版本
)
最小宽度限定符可让您通过指定某个最小宽度(以 dp 为单位)来定位屏幕。例如,标准 7 英寸平板电脑的最小宽度为 600 dp,因此如果您要在此类屏幕上的用户界面中使用双面板(但在较小的屏幕上只显示列表),您可以使用上文中所述的单面板和双面板这两种布局,但您应使用 sw600dp 指明双面板布局仅适用于最小宽度为 600 dp 的屏幕,而不是使用 large 尺寸限定符。
最小宽度(Smallest-width)限定符
(3)布局别名
为了解决文件名的重复从而带来一些列后期维护的问题,我们使用 布局别名 方案。
通过以上两点,大家也会发现一个问题:
适配手机没问题。但是适配平板发现Android3.2前后的这两个文件内容是一样的,只是文件名不同而已。
适配手机的单面板(默认)布局:res/layout/main.xml
适配尺寸>7寸平板的双面板布局(Android 3.2前):res/layout-large/main.xml
适配尺寸>7寸平板的双面板布局(Android 3.2后)res/layout-sw600dp/main.xml
解救方案:取一个别名就好了,示例如下:
布局别名
这样两个layout.xml都只是引用了@layout/main_twopanes,就避免了重复定义布局文件的情况
(4)屏幕方向(Orientation)限定符。
根据屏幕方向进行布局的调整。
某些布局会同时支持横向模式和纵向模式,但我们可以通过调整优化其中大部分布局的效果。每种屏幕尺寸和屏幕方向下的布局行为方式如下所示:
解决方案:
第一步:先定义类别:单/双面板、是否带操作栏、宽/窄
定义在 res/layout/ 目录下的某个 XML 文件中
第二步:再进行相应的匹配:屏幕尺寸(小屏、7寸、10寸)、方向(横、纵)
使用布局别名进行匹配
示例代码如下图所示:
屏幕方向(Orientation)限定符
这里没有完全把全部尺寸匹配类型的代码贴出来,大家可以自己去尝试把其补充完整。
4.1.2. 布局组件适配 使得布局组件自适应屏幕尺寸。
4.1.3. 图片资源适配 使得图片资源在不同屏幕密度上显示相同的像素效果。
在实际开发中一个按钮的背景图片必须能够随着按钮大小的改变而改变。使用普通的图片将无法实现这个效果,因为运行时会对图片均匀地拉伸或压缩。
nine-patch图片
),后缀名是.9.png
,它是一种被特殊处理过的PNG图片,设计时可以指定图片的拉伸区域和非拉伸区域;使用时,系统就会根据控件的大小自动地拉伸你想要拉伸的部分。- 1.必须使用UI给的图片格式(.9.png后缀),随意更改后缀使用在项目中会报错,因为系统就是根据这个来区别nine-patch图片和普通的PNG图片的。
- 2.部分nine-patch图片在Android Studio项目中不能识别,会报错,需要谨慎使用。下面一张图看看使用
使用 nine-patch 图片的效果
nine-patch图片
制作请参考我的博客:
nine-patch图片的制作
4.1.4. 用户界面流程适配 根据屏幕的配置来加载相应的用户界面流程。
① 确定当前布局。示例如下:
由于每种布局的实施都会稍有不同,因此我们需要先确定当前向用户显示的布局。
例如,我们可以先了解用户所处的是“单面板”模式还是“双面板”模式。
确定当前布局
② 根据当前布局做出响应。示例如下:
有些操作可能会因当前的具体布局而产生不同的结果。
例如,在新闻阅读器示例中,如果用户界面处于双面板模式下,那么点击标题列表中的标题就会在右侧面板中切换到相应报道(Fragment);但如果用户界面处于单面板模式下,那么上述操作就会启动一个独立Activity:
根据当前布局做出响应
③ 重复使用其他 Activity 中的 Fragment。示例如下:
例如,在新闻阅读器示例中,对于较大的屏幕,新闻报道文本会显示在右侧 Fragment 面板中;但对于较小的屏幕,这些文本就会以独立 Activity 的形式存在。
重复使用其他 Activity 中的 Fragment
④ 处理屏幕配置变化。示例如下:
如果我们使用独立Activity实施界面的独立部分,那么请注意,我们可能需要对特定配置变化(例如屏幕方向的变化)做出响应,以便保持界面的一致性。
例如,在运行 Android 3.0 或更高版本的标准 7 英寸平板电脑上,如果新闻阅读器示例应用运行在纵向模式下,就会在使用独立Activity 显示新闻报道;但如果该应用运行在横向模式下,就会使用双面板布局。
处理屏幕配置变化
4.2.1.布局控件适配 使得布局组件在不同屏幕密度上显示相同的像素效果。
解决方案有以下两种:
有下面一种场景:
RelativeLayout布局里面,水平方向上放置两个按钮,一个是150dp左对齐,另外一个是200dp右对齐。在屏幕总宽度为360dp的Nexus5上中间有10dp的间隙。但同样地设置在Nexus S(屏幕宽度是320dp),会发现,两个按钮会重叠,因为320dp<200+150dp。
如图:
Nexus5 效果
Nexus S 效果
从上面可以看出,由于Android屏幕设备的多样性,如果使用dp来作为度量单位,并不是所有的屏幕的宽度都具备相同的dp长度。
dp解决了同一数值在 不同分辨率 中展示 相同尺寸大小 的问题(即屏幕像素密度匹配问题),但却没有解决设备 尺寸大小匹配 的问题。(即屏幕尺寸匹配问题)。
注意:屏幕宽度和像素密度没有任何关联关系。
- 从上面案例看出,因为屏幕密度(分辨率)不一样,所以不能用固定的px;因为屏幕宽度不一样,所以要小心的用dp。
- 因为本质上是希望使得布局组件在不同屏幕密度上显示相同的像素效果,那么,之前是绕了个弯使用dp解决这个问题,那么到底能不能直接用px解决呢?当然是可以的。根据不同屏幕密度,控件选择对应的像素值大小。解决方法是: **百分比适配。**
- 先说一下**缺点**: 使用像素作为计量单位的适配方式,应该能进行90%的适配了,但其
1.由于实际上还是使用px作为长度的度量单位,所以和google的要求使用dp作为度量单位会有所背离
2.必须尽可能多的包含所有分辨率,因为这个是使用这个方案的基础,如果有某个分辨率缺少,将无法完成该屏幕的适配
3.过多的分辨率像素描述xml文件会增加软件包的大小和维护的难度
★ 1.以某一分辨率为基准,生成所有分辨率对应像素数列表
现在我们以320x480的分辨率为基准:
将屏幕的宽度分为320份,取值为x1x320,将屏幕的高度分为480份,取值为y1y480
然后生成该分辨率对应像素数的列表,如下图:
基准分辨率像素列表
找到基准后,是时候把其他分辨率补全了,以下是以1080x1920的分辨率为例:
关于自动生成values文件夹,这里推荐两个工具:
① AndroidPixelDimenGenerator ,使用方式可以百度一下,这不是本文的重点。
② 张鸿洋大神写的autolayout.jar这个工具,使用方法如下图所示:
自动生成values文件夹以及对应的dimens.xml文件.gif
★ 2.将生成像素数列表存放在res目录下对应的values文件下,这个步骤上面的动态图已经做了。
注意事项:
★ 3.根据UI设计师给出设计图上的尺寸,找到对应像素数的单位,然后设置给控件即可。如下图:
<FrameLayout >
<Button
android:layout_gravity="center"
android:gravity="center"
android:text="@string/hello_world"
android:layout_width="@dimen/x160"
android:layout_height="@dimen/y160"/>
</FrameLayout>
4.2.2.图片资源适配 使得图片资源在不同屏幕密度上显示相同的像素效果。
谷歌官方给出的屏幕密度对应的图标尺寸对照表
比如说,如果我们为 xxhdpi 设备生成了144_144 px尺寸的图片,就应该按照相应比例地为 hdpi、xhdpi 和 xxhdpi 设备分别生成 72_72 px 、96_96 px 和 192_192 px 尺寸的图片。
★ 2.将生成的图片文件放在 res/ 下的相应子目录中(mdpi、hdpi、xhdpi、xxhdpi),系统就会根据运行您应用的设备的屏幕密度自动选择合适的图片。
★ 3.通过引用 @drawable/id,系统都能根据相应屏幕的 屏幕密度(dpi)自动选取合适的位图。
1.如果是.9图或者是不需要多个分辨率的图片,放在drawable文件夹即可。
2.对应分辨率的图片要正确的放在合适的文件夹,否则会造成图片拉伸等问题。
1. 每套分辨率出一套图,为美工或者设计增加了许多工作量
2. 对Android工程文件的apk包变的很大
public class ScreenSizeUtil {
public static int getScreenWidth(Activity activity) {
return activity.getWindowManager().getDefaultDisplay().getWidth();
}
public static int getScreenHeight(Activity activity) {
return activity.getWindowManager().getDefaultDisplay().getHeight();
}
}
③.使用第三方的屏幕适配框架。
`
本文参考文章: