Android屏幕适配基本概念

目录

一、为什么要适配

由于Android系统的开放性,任何用户、开发者、硬件厂商、运营商都可以对Android系统和硬件进行定制,修改成他们想要的样子。 那么这种“碎片化”到达什么程度呢?

img

以上每一个矩形都代表一种机型,且它们屏幕尺寸、屏幕分辨率大相径庭。随着Android设备的增多,设备碎片化、系统碎片化、屏幕尺寸碎片化、屏幕碎片化的程度也在不断加深。

备注:

  1. Android系统碎片化:基于Google原生系统,小米定制的MIUI、魅族定制的flyme、华为定制的EMUI等等;
  2. Android机型屏幕尺寸碎片化:5寸、5.5寸、6寸等等;
  3. Android屏幕分辨率碎片化:320x480、480x800、720x1280、1080x1920等;

当Android系统、屏幕尺寸、屏幕密度出现碎片化的时候,就很容易出现同一元素在不同手机上显示不同的问题。试想一下这么一个场景: 为4.3寸屏幕准备的UI设计图,运行在5.0寸的屏幕上,很可能在右侧和下侧存在大量的空白;而5.0寸的UI设计图运行到4.3寸的设备上,很可能显示不下。

为了保证用户获得一致的用户体验效果,使得某一元素在Android不同尺寸、不同分辨率的、不同系统的手机上具备相同的显示效果,能够保持界面上的效果一致,我们需要对各种手机屏幕进行适配!

二、基本概念

1、像素(px):

  • 含义:通常所说的像素,就是CCD/CMOS上光电感应元件的数量,一个感光元件经过感光,光电信号转换,A/D转换等步骤以后,在输出的照片上就形成一个点,我们如果把影像放大数倍,会发现这些连续色调其实是由许多色彩相近的小方点所组成,这些小方点就是构成影像的最小单位“像素”(Pixel)。简而言之,像素就是手机屏幕的最小构成单元

  • 单位:px(pixel),1px = 1像素点 一般情况下UI设计师的设计图会以px/dp作为统一的计量单位。

2、分辨率:

  • 含义:手机在横向、纵向上的像素点数总和 一般描述成 宽*高 ,即横向像素点个数 * 纵向像素点个数(如1080 x 1920)。

  • 单位:px(pixel),1px = 1像素点

3、屏幕尺寸(inch):

  • 含义:手机对角线的物理尺寸

  • 单位 英寸(inch),一英寸大约2.54cm 常见的尺寸有4.7寸、5寸、5.5寸、6寸

4、屏幕像素密度(dpi):

  • 含义:每英寸长所占的像素点数。 例如每英寸内有160个像素点,则其像素密度为160dpi。

  • 单位:dpi(dots per inch)

  • 计算公式: 像素密度 = 像素 / 尺寸 (dpi = px / in)

  • 标准屏幕像素密度(mdpi): 每英寸长度上还有160个像素点(160dpi),即称为标准屏幕像素密度(mdpi)。

至于为什么标准像素密度要设置为160?

简单说就是为了可以让像素取整。 下面是具体解释

实际开发当中,我们经常需要对这几个尺寸进行相互转换(比如先在某个分辨率下完成设计,然后缩放到其他尺寸微调后输出),一般按照 dpi 之间的比例即 2:1.5:1:0.75   来给界面中的元素来进行尺寸定义。

也就是说如果以 160 dpi 作为基准的话,只要尺寸的 DP 是 4 的公倍数,XHDPI 下乘以 2,HDPI 下乘以 1.5,LDPI 下乘以 0.75 即可满足所有尺寸下都是整数 pixel 。

但假设以 240 dpi 作为标准,那需要 DP 是 3 的公倍数,XHDPI 下乘以 1.333,MDPI 下乘以 0.666 ,LDPI 下除以 2

而以 LDPI 和 XHDPI 为基准就更复杂了,所以选择 160 dpi

密度类型 代表的分辨率(PX) 屏幕像素密度(DPI)
低密度(ldpi) 240 x 320 120
中密度(mdpi) 320 x 480 160
高密度(hdpi) 480 x 800 240
超高密度(xhdpi) 720 x 1280 320
超超高密度(xxhdpi) 1080 x 1920 480

屏幕尺寸、分辨率、像素密度三者关系

一部手机的分辨率是宽x高,屏幕大小是以寸为单位,那么三者的关系是:

img

假设一部手机的分辨率是1080x1920(px),屏幕大小是5寸

img

5、密度无关像素(dp):

  • 含义:density-independent pixel,叫dp或dip,与终端上的实际物理像素点无关

  • 单位:dp,可以保证在不同屏幕像素密度的设备上显示相同的效果,是安卓特有的长度单位。

  • 场景例子:假如同样都是画一条长度是屏幕一半的线,如果使用px作为计量单位,那么在480x800分辨率手机上设置应为240px;在320x480的手机上应设置为160px,二者设置就不同了;如果使用dp为单位,在这两种分辨率下,160dp都显示为屏幕一半的长度。

  • dp与px的转换:1dp = (dpi / 160 ) * 1px;

密度类型 代表的分辨率(PX) 屏幕密度(DPI) 换算
低密度(ldpi) 240 x 320 120 1dp = 0.75px
中密度(mdpi) 320 x 480 160 1dp=1px
高密度(hdpi) 480 x 800 240 1dp=1.5px
超高密度(xhdpi) 720 x 1280 320 1dp=2px
超超高密度(xxhdpi) 1080 x 1920 480 1dp=3px

6、独立比例像素(sp):

含义:scale-independent pixel,叫sp或sip

单位:sp,字体大小专用单位 Android开发时用此单位设置文字大小,可根据字体大小首选项进行缩放; 推荐使用12sp、14sp、18sp、22sp作为字体大小,不推荐使用奇数和小数,容易造成精度丢失,12sp以下字体太小。

7、sp 与 dp 的区别:

dp只跟屏幕的像素密度有关;

sp和dp很类似但唯一的区别是,Android系统允许用户自定义文字尺寸大小(小、正常、大、超大等等),当文字尺寸是“正常”时1sp=1dp=0.00625英寸,而当文字尺寸是“大”或“超大”时,1sp>1dp=0.00625英寸。类似我们在windows里调整字体尺寸以后的效果——窗口大小不变,只有文字大小改变。

追到android源码,发现系统内部用applyDimension() (路径:android.util.TypedValue.applyDimension())将所有单位都转换成px 再处理:

/*
 *
 * @param unit The unit to convert from.
 * @param value The value to apply the unit to.
 * @param metrics Current display metrics to use in the conversion -- 
 *                supplies display density and scaling information.
 * 
 * @return The complex floating point value multiplied by the appropriate 
 * metrics depending on its unit. 
 */
 public static float applyDimension(int unit, float value,DisplayMetrics metrics){
 switch (unit) {
 case COMPLEX_UNIT_PX:
 return value;
 case COMPLEX_UNIT_DIP:
 return value * metrics.density;
 case COMPLEX_UNIT_SP:
 return value * metrics.scaledDensity;
 case COMPLEX_UNIT_PT:
 return value * metrics.xdpi * (1.0f/72);
 case COMPLEX_UNIT_IN:
 return value * metrics.xdpi;
 case COMPLEX_UNIT_MM:
 return value * metrics.xdpi * (1.0f/25.4f);
 }
 return 0;
 }
​
 可以发现dp和sp的区别在于density和scaledDensity两个值上;
​
 /**
 * The logical density of the display.  This is a scaling factor for the
 * Density Independent Pixel unit, where one DIP is one pixel on an
 * approximately 160 dpi screen (for example a 240x320, 1.5"x2" screen), 
 * providing the baseline of the system's display. Thus on a 160dpi screen 
 * this density value will be 1; on a 120 dpi screen it would be .75; etc.
 *
 * 

This value does not exactly follow the real screen size (as given by * {@link #xdpi} and {@link #ydpi}, but rather is used to scale the size of * the overall UI in steps based on gross changes in the display dpi. For * example, a 240x320 screen will have a density of 1 even if its width is * 1.8", 1.3", etc. However, if the screen resolution is increased to * 320x480 but the screen size remained 1.5"x2" then the density would be * increased (probably to 1.5). * * @see #DENSITY_DEFAULT */ public float density; ​ /** * A scaling factor for fonts displayed on the display. This is the same * as {@link #density}, except that it may be adjusted in smaller * increments at runtime based on a user preference for the font size. */ public float scaledDensity;

8.区分dpi、dp、dip、px、density、分辨率

  • dpi:dots per inch , 直接来说就是一英寸多少个像素点。常见取值 120,160,240。我一般称作像素密度,简称密度

  • density:可以理解为像素密度,手机屏幕dpi与标准mdpi(160dpi)的比值,比如160dpi的手机,density=1,440dpi的手机,density=2.75

  • dp/dip:density-independent pixels 密度无关像素,就是Google工程师们给android定义的一个长度单位,使用这种长度单位,可以使界面元素在不同密度(dpi)的屏幕上保持近似的物理尺寸大小

  • px:pixel 像素,屏幕上显示元素的最小单位,比如屏幕分辨率1920*1080 px

  • 分辨率:屏幕宽高的像素 比如:1920*1080

9.px、dpi、density各单位的计算

Metrics

在android里面,获取一个窗口的metrics,里面有这么几个值

metrics.densityDpi;
metrics.density; 

densityDpi : 就是我们常说的dpi,一英寸占多数像素。

density:密度(density=dpi/160) 常见取值1.0 1.5 。

计算dpi

假设一部手机屏幕为4英寸,分辨率为800*480,计算dpi

dpi是指每英寸长所占的像素数量

4英寸是指屏幕对角线长度为4寸

分辨率高800px、宽480px

那么根据勾股定理可以求得对角线的像素数量

(800平方+480平方)开根号 = 屏幕对角线像素数量

屏幕对角线像素数量 / 4 = dpi

800平方 + 480平方 = 870400

870400开方 = 932.952

932.952 / 4 = 233 (dpi)

也就是说这部手机的dpi是233,接近hdpi

dp与px换算

为什么要知道这个呢? 因为针对不同的手机dp与px的换算大小是不一样的,我们有必要知道是什么决定了他们的大小

换算公式如下:

1 = dpi/160

(dp) (px)

1是指1dp

160是标准密度,也就是mdpi

所以我们能看出来,当dpi为160的时候 1dp=1px,dpi为240(hdpi)时,1dp=1.5px

我们再将这个公式变一下,我们知道density=(dpi/160),是不是和上边的公式很像,这个公式就可以变为

density*dp = px

可以理解为dp乘上密度就是px

三、适配方案

屏幕适配问题的本质是使得布局、布局组件在Android不同尺寸、不同分辨率的手机上具备相同的显示效果,下面我将分几个方面来谈谈如何去适配。

3.1 关于布局组件的适配:

3.1.1 避免使用像素(px)指定尺寸

由于各种屏幕的像素密度都有所不同,因此相同数量的像素在不同设备上的实际大小也会有所差异,这样使用像素(px)定义布局尺寸就会产生问题。 因此,请务必使用密度无关像素 dp 或独立比例像素 sp 单位指定尺寸。

备注:在生产过程中,厂家不会完全按照屏幕密度标准去生产Android设备,会在Google的标准周围浮动变化,或是偏离Google的屏幕密度标准比较大,再加上理论计算(开方)造成的误差,实际上使用dp作为单位是不能完完全全的完成适配操作。

3.1.2 使用相对布局或线性布局,不要使用绝对布局

对于线性布局(Linearlayout)、相对布局(RelativeLayout)、帧布局(FrameLayout)、绝对布局(AbsoluteLayout)以及新增的加强版帧布局(CoordinatorLayout)需要根据需求进行选择,没有绝对而言。 ​ 但因为RelativeLayout讲究的是相对位置,即使屏幕的大小改变,视图之前的相对位置都不会变化,与屏幕大小无关,灵活性很强,而LinearLayout法准确地控制子视图之间的位置关系,只能简单的一个挨着一个地排列,所以,对于屏幕适配来说,使用相对布局(RelativeLayout)将会是更好的解决方案,至于绝对布局由于适配性极差,所以极少使用。

3.1.3 使用wrap_content、match_parent、权重

使用 “wrap_content” 和 “match_parent” 尺寸值而不是硬编码的尺寸,系统会自动计算相应的数值,视图就会相应地使用自身所需的空间或填满可用空间,让布局正确适应各种屏幕尺寸和屏幕方向,组件的权重比同理。

3.1.4 使用minWidth、minHeight、lines等属性

很多时候我们显示的数据都是由后台返回的,再由我们加工处理后去适配我们的组件,这些数据的长度我们是无法确定的,而正常情况下我们构思的布局都仅是适用于理想的情况下,为了保证界面的对齐、数据显示完整等等的原因,我们需要在构思布局时增加对组件最小宽高度、行数等属性的设置,确保在特殊的数据下不会破坏我们的整体布局。

3.1.5 使用dimens

组件的长宽我们可以通过dimens来定义,不同的屏幕尺寸可以定义不同的数值,或者是不同的语言显示我们也可以定义不同的数值,因为翻译后的长度一般都不会跟中文的一致。

3.2 成熟的适配框架

3.2.1 生成多套Dimens适配

最常用效果最好的适配方案

3.2.2 针对density转换px适配(今日头条的适配方案)

最便捷的适配方案

AndroidAutoSize

https://github.com/JessYanCoding/AndroidAutoSize

https://www.jianshu.com/p/4aa23d69d481

你可能感兴趣的:(Android屏幕适配基本概念)