Platform: RK3399
OS: Android 7.1
Kernel: v4.4.83
现象:
移植好LVDS屏幕之后发现桌面上显示的ICON偏移,并且导航栏也看不到了。
正常应该是这些ICON都是底部显示。
原因:
ppi设置不对,修改ro.sf.lcd_density的值即可。
原理说明:
关于ppi,网上看到一篇文章介绍非常到位,这里引用记录:
在进行适配分析前,必须要了解一些概念,这样才能明白之后说的内容。那就是屏幕size,屏幕分辨率,px,dp,dip,sp,dpi,ppi,densityDpi,density。
看到这么多东西可能有人就烦了,没办法,只有理解了这些东西才能理解如何适配。对于这些词,网上也已经说了很多很多,不过好几年过去了,发现还是没人系统的全面的把这个总结一下,所以今天我就来做这个工作。
屏幕size我们一般以英寸来计算,1英寸=2.54厘米。一般来说的屏幕尺寸指屏幕对角线的尺寸。
比如说屏幕是5英寸的,那么既不是屏幕宽,也不是屏幕高,而是屏幕对角线的长度。
屏幕分辨率就是屏幕所含的像素数,比如1080*1920是指屏幕的宽有1080像素,高有1920像素。当然这个像素的单位就是我们要说的px。
px(Pixel)就是像素的单位,全彩显示屏,三个或是四个发光点(两红一绿一蓝)为一像素。
dpi(Dot Per Inch)每英寸所含的点数目。最初用于衡量打印物上每英寸的点数密度,就是说你的打印机可以在一英寸内打多少个点。DPI值越小图片越不精细。
当DPI的概念用在计算机屏幕上时,就应称之为ppi(Pixels Per Inch)。
有了dpi的说明,ppi就比较好理解了,就是计算机屏幕上每英寸可以显示的像素点的数量。网上好多人在辩论dpi和ppi的区别(通过上面的dpi的说明,实际我也说了区别了),不过在Android上这两点不用区分,因为首先概念是一样的,其次我们可以在Android的源码中找到各种命名和注释都是部分ppi和dpi的,所以你说 dpi也好,ppi也好,大家都能理解。
既然ppi是没英寸的像素数,而屏幕大小是指对角线长度,所以ppi的计算是对角线的逻辑像素数除以屏幕尺寸。为什么说是逻辑像素呢?因为有人在较真,说ppi就是每英寸的像素数,所以应该用屏幕宽尺寸除以屏幕宽像素或屏幕高尺寸除以屏幕高像素,实际不必这么想,既然说的屏幕尺寸是指对角线,那么我们就应该用逻辑上的对角线上的像素来除以对角线的尺寸,但是对角线上的不一定正好就是个整数,所以我说逻辑上的,计算当然就是勾股定理。
那么最终的计算公式就是:ppi=(√(横向分辨率2+纵向分辨率2))/屏幕尺寸)。
说完上面的我们就可以来说dp和dip(device independent pixels)了,实际dp和dip是同一个意思,一回事。dp就是设备独立像素。是一种基于屏幕密度的抽象单位。例如在每英寸160个像素的设备上,也就是ppi=160的设备显示器上,1dp=1px。
如果是ppi=320的,那1dp=2px。所以说px=dp*(ppi/160),或者dp=px160/ppi。对于这个160这个数字怎么来的,有人说是第一代Android手机T-Mobile G1就是160ppi,所以用了160这个数字作为基数,不过有的人计算了G1的ppi实际是180,有的人也说可能是因为第一代iPhone是160ppi,这我就不去追究了,反正知道160ppi是基数就好了。
有了dp这个单位就太好了,这也是Google建议大家在写布局时的宽高尺寸使用单位。可以想象一下,如果我们用px做单位的话。假如现在有两个手机屏幕有同样的尺寸,但是其中一个是480320像素的,一个是960640像素的。
如果此时我们添加了一个按钮,按钮大小是40px160px的,那么我们在第一个手机上看到的宽将是屏幕的1/2,而第二个却是屏幕的1/4。如果这样写的话,随着屏幕的尺寸不变但是像素的增多,dpi也在增加,像素的密度就会高,相同的px就会显示的很小。
这样最终我们将无法使多个屏幕的显示效果都满意。但是使用dp就不一样了,假如我们有两个手机还是屏幕尺寸一样,比如是1.5英寸2英寸的,分辨率分别是240320和480640,它们的ppi分别是160和320,如果我现在有个控件是10dp40dp的,那么由之前的公式可以得知,在第一个手机上显示的像素是10px40px,而第二个手机上是20px80px,宽度都是占屏幕的1/8。
这样我们在视觉上就不会觉得哪个手机上的控件有问题了,不会像素密度大的显示的小,像素密度小的显示的大了。同理,当你像素不变,但是屏幕尺寸变化的时候也是同样的道理,dp的显示总是和你的密度无关。
我们来看几个数据的对比:如果ppi是160,那么1dp=1px,因为ppi是160,所以 160px是1英寸,1px就是1/160英寸,也就是1dp是1/160英寸;如果ppi是320,那么1dp=2px,因为ppi是320,所以 320px是1英寸,2px就是2/320英寸,也就是1dp是1/160英寸;如果ppi是n,那么1dp=n/160px 因为ppi是n 所以 npx是1英寸,n/160px就是n/160/n英寸,也就是1dp是1/160英寸。是不是看出了什么!?对,1dp就是1/160英尺!!!(对于这个结论,我们下面再进行更加准确的讨论)如果仔细的研究上面的计算公式也是可以得出这个结论的。
可以看到,有了dp,我们就几乎不用关心屏幕的密度是怎么样的了,所以是设备独立像素。
densityDpi实际就是dpi或者是ppi,只不过它以160为基准,预置了几种屏幕分辨率等级,比如我们总是一直见的DENSITY_LOW=120,DENSITY_MEDIUM = 160,DENSITY_HIGH = 240,DENSITY_XHIGH = 320,DENSITY_XXHIGH = 480,DENSITY_XXXHIGH = 640。
这些数据直接反应了我们手机的像素密度,如果我们看一个真实机(非虚拟机),在/system/build.prop目录中写明了densityDpi的值,系统会读取这个值,然后提供我们对应的数据。
而density是我们非常熟悉的,我们进行px和dp的转换的时候经常用这个值,它是DisplayMetrics类中的变量。density的计算公式是:density=ppi/160,也就是我们上面说的预置的densityDpi/160,所以它可能的值就是0.75,1,1.5,2,3,4。
原作者:KrisFei