前言
每个Android程序员都会遇见一个棘手的问题,那就是手机适配。因为现在出现了许多分辨率的手机,所以我们必须得考虑到各种分辨率的手机适配,这对于程序员来说是一个必须要解决的麻烦。
对于适配各种尺寸的屏幕而苦恼;出现一个新的机型而修改这数不尽的dimens以及layout;为了UI给的奇葩尺寸的设计图而绞尽奶汁计算距离。如果你还在为这些事情而苦恼,希望看完这篇文章后,可以帮你减少一些开发的时间。
Android屏幕适配方案
1.官方适配方案
dp。dp是Android开发中特有的一个单位。与px不同,dp是基于屏幕像素密度的一种单位。在密度低的屏幕上或许1dp=1px,但在密度高的屏幕上可能1dp=4px。编写布局xml时,如果一个控件的长宽都使用dp来指定,那么能确保该控件在各种大小与分辨率的屏幕下的绝对大小都大致相当。也就是说无论在pad下还是大小屏手机下,我们实际看到的该控件的大小是差不多的:
资源目录名。上图可见虽然使用dp确保了控件在不同屏幕中的绝对大小一致。这样的好处在于,在大小相近的屏幕中,无论分辨率多大都不会对布局造成影响;但是当屏幕大小相差较大时,仅保证控件的绝对大小看起来就有些问题了。在res目录下可以给各资源目录都加上例如’-1920x1080’等后缀来适配不同的屏幕,具体规则可见官网文档。这样可以针对不同的屏幕提供不同的布局,甚至针对pad与手机提供两套完全不同的布局样式。但是通常情况下,设计师并不会对不同屏幕提供不同的设计图,他们的需求仅仅是不同屏幕下控件对屏幕的相对大小一致,所以dp并不能满足这一点,而对各种屏幕适配一遍又显得略为繁琐,并且修改也较为麻烦。通常我们需要的适配是这样的:
百分比布局支持库。没有使用过,但是deprecated in API level 26.0.0-beta1。
ConstraintLayout。百分比支持库deprecated之后推荐使用的布局,看起来似乎略复杂。
2.玩家适配方案
广大玩家的适配目的很明确,目的就是要确保控件在不同屏幕的相对大小一致,看起来一毛一样的。以一位大神玩家的两种适配方案为例:
扩展性较差。对于每一种ViewGroup都要对应编写对应的AutoLayout进行扩展,对于各View的每个需要适配的属性都要编写代码进行适配扩展;
在onMeasure阶段进行数值计算。消耗性能,并且这对于非LayoutParams中的属性存在较多不合理之处。比如在onMeasure时对TextView的textSize进行换算并setTextSize,那么玩家在代码中动态设置的textSize都会失效,因为在每次onMesasure时都会重新被AutoLayout重新设置覆盖。
方案一、编写脚本将长度转换成各分辨率下的长度,缺点是难以覆盖市面上的所有分辨率。
方案二、AutoLayout支持库。该库的想法非常好:对照设计图,使用px编写布局,不影响预览;绘制阶段将对应设计图的px数值计算转换为当前屏幕下适配的大小;为简化接入,inflate时自动将各Layout转换为对应的AutoLayout,从而不需要在所有的xml中更改。但是同时该库也存在问题。
Android屏幕适配详解
一、关于布局适配建议
1、不要使用绝对布局
2、尽量使用match_parent 而不是fill_parent 。
3、能够使用权重的地方尽量使用权重(android:layout_weight)
4、如果是纯色背景,尽量使用android的shape 自定义。
5、如果需要在特定分辨率下适配,可以在res目录上新建layout-HxW.xml的文件夹。比如要适配1080*1800的屏幕(魅族MX3采用此分辨率)则新建layout-1800x1080.xml的文件夹,然后在下面定义布局。Android系统会优先查找分辨率相同的布局,如果不存在则换使用默认的layout下的布局。
6、关于长宽设置最好是3的倍数,最好是偶数。
二、基本概念
px : 英文单词pixel的缩写,意为像素,屏幕上的点。我们通常所说的分辨率如480X800就是指的像素。像素是最小的独立显示单位,px均为整数,不会出现0.5px的情况。
in : 英寸,是屏幕的物理尺寸,手机屏幕大小如1.6英寸、1.9英寸、2.2英寸,都是指的对角线的长度。
dpi:Dots Per Inch的缩写, 每英寸点数,即每英寸包含像素个数。如320X480分辨率宽2英寸,高3英寸, 每英寸包含的像素点的数量为320/2=160dpi(横向)或480/3=160dpi(纵向),160就是这部手机的dpi
density : 屏幕密度,density和dpi的关系为 density = dpi/160。
**dp **: 即dip,设备独立像素,device independent pixels的缩写。dp = density * px 。
**sp **: 和dp很类似,一般用来设置字体大小,和dp的区别是它可以根据用户的字体大小偏好来缩放。
四种屏幕尺寸分类::small, normal, large, and xlarge
四种密度分类:ldpi (low), mdpi (medium), hdpi (high), and xhdpi (extra high)(普通屏幕:ldpi是120,mdpi是160,hdpi是240,xhdpi是320)
三、如何做到自适应屏幕大小呢?
1)界面布局方面
需要根据物理尺寸的大小准备5套布局,layout(放一些通用布局xml文件,比如界面中顶部和底部的布局,不会随着屏幕大小变化,类似windos窗口的title bar),layout-small(屏幕尺寸小于3英寸左右的布局),layout-normal(屏幕尺寸小于4.5英寸左右),layout-large(4英寸-7英寸之间),layout-xlarge(7-10英寸之间)
2)图片资源方面
需要根据dpi值准备5套图片资源,drawable,drawalbe-ldpi,drawable-mdpi,drawable-hdpi,drawable-xhdpi
Android有个自动匹配机制去选择对应的布局和图片资源
四、获取屏幕分辨率信息的方法:
第一种:
DisplayMetrics metrics = new DisplayMetrics();
Display display = activity.getWindowManager().getDefaultDisplay();
display.getMetrics(metrics);
int width =metrics .widthPixels; // 屏幕宽度(像素)
int height =metrics .heightPixels; // 屏幕高度(像素)
float density =metrics .density; // 屏幕密度(0.75 / 1.0 / 1.5)
int densityDpi =metrics .densityDpi; // 屏幕密度DPI(120 / 160 / 240)
第二种:
Display mDisplay = getWindowManager().getDefaultDisplay();
int W = mDisplay.getWidth();
int H = mDisplay.getHeight();
五、其它说明
1、在xhdpi里面放一张120px*120px的图片,图片使用wrap_content设置长宽与设置长宽为60dp效果一样。只提供一套图片时,目前xhdpi是最好的选择,主分辨率是720P。
2、切图方面:
- 长宽最好是3的倍数(根据android的推荐logo图标的大小是48(mdpi),72(hdpi),96(xhdpi)得出的最小公约数)。
- 长宽最好是偶数。因为奇数在进行等比压缩的时候可能有问题。
- 根据上面两条,如果长宽是6的倍数最理想。
- 如果可以拉伸而不改变设计意图的情况下,比如纯色背景,则使用android的9path工具制作成.9的图片。
3、屏幕密度、像素和实际大小的比例关系。他们的关系是2:3,于是你需要按照1.5倍比例制作图标,比如你在480800的设计稿上切下来一个2020像素的图,那么你就需要制作一个等比放大成3030像素的图标,这样同一个图标在480800的屏幕和7201280的屏幕上显示的实际大小才一样。同理,如果你需要适配xxhdpi则需要在2020的基础上制作一个等比放大成40*40像素的图标。
4、关于图标的目录,480*800切下来的图我们放在drawable-hdpi目录下,按照2:3放大的图标放在drawable-xhdpi目录下,按照2倍放大的图标放在drawable-xxhdpi目录下。
android会根据手机的密度优先查找对应的目录的资源,如果没有这个文件夹,则查找与其最接近的对应密度文件夹。
5、demins的使用。demins在value文件夹下,相关配置可以在values-hpdi,values-mdpi,values-ldpi三种文件夹中的dimens.xml文件进行设置。
这是一份屏幕适配解决方案大纲,希望对小伙伴们有一定的帮助。
资料领取
关注我后台私信回复【干货分享】
领取获取往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术
网友评论