做安卓已经几年了,其中涉及到的各种单位依旧容易混淆,网络上有许多相关的文章,甚至不同的文章相关的概念解释也略有出入,现对一些概念及屏幕适配相关的信息提出我个人的一些理解
相关尺寸的概念
名词 | 解释 |
Px (Pixel像素) | 不同设备显示效果相同。这里的“相同”是指像素数不会变,比如指定UI长度是100px,那不管分辨率是多少UI长度都是100px。也正是因为如此才造成了UI在小分辨率设备上被放大而失真,在大分辨率上被缩小。 |
Screen Size (屏幕尺寸) | 一般所说的手机屏幕大小如5.0英寸、5.5英寸,都是指的对角线的长度。 |
Resolution (分辨率) | 指手机屏幕水平和垂直方向上的像素个数。比如分辨率是1080*1920,则指设备水平方向有1080个像素点,垂直方向有1920个像素点。一般是width*height(宽在前,高在后) |
Dpi (dots per inch 像素密度) | 指每英寸中的像素数。如160dpi指手机水平或垂直方向上每英寸距离有160个像素点。假定设备分辨率为320*240,屏幕长2英寸宽1.5英寸,dpi=320/2=240/1.5=160,计算公式为 dpi = 该值对应于DisplayMetrics类中属性densityDpi的值 |
Density (密度) | 在DisplayMetrics类中属性density的值为dpi/160,可用于px与dip的互相转换 |
Dip (Device-independent pixel,设备独立像素) | 同dp,可作长度单位,不同设备有不同的显示效果,这个和设备硬件有关,不依赖像素。dip和具体像素值的对应公式是dip值 =dpi/160* px,可以看出在dpi(像素密度)为160dpi的设备上1px=1dip,这也是在安卓设备中规定的基准。 |
Sp (ScaledPixels 缩放像素) | 主要用于字体显示(best for textsize)。根据 google 的建议,TextView 的字号最好使用 sp 做单位,而且查看TextView的源码可知 Android 默认使用 sp 作为字号单位。 |
比如有如下屏幕:
- 屏幕1:分辨率=720x1280,dpi=320
- 屏幕2:分辨率=1080x1920,dpi=480
如果要实现一个view的宽度占屏幕1宽度的一半
对于屏幕1:view的宽度是360px,则对应的dp = 360/(320/160),为180dp。
对于屏幕2:view的宽度是540px,则对应的dp = 540/(480/160),为180dp。
所以,使用180dp就可以同时在两个屏幕上显示相同的效果了。
然而在android开发中所说的dpi的值并不是物理定义的,而是系统文件写进去的,所以这个值是可以被修改的。另一层意思是,dpi并不是由分辨率和屏幕尺寸计算出来的固定值。比如当前常见的一种机型分辨率是1080x1920,尺寸是5.15英寸,dpi是480。按照dpi的定义,使用这个分辨率和尺寸计算dpi的话,结果并不是480。所以对分辨率和尺寸都相同的手机,dpi值不一定相同,完全看手机厂商如何定义。不过,为了使显示效果最好,一般比较标准的手机dpi和分辨率都和下表一致:
ldpi | mdpi | hdpi | xhdpi | xxhdpi | |
分辨率 | 240*320 | 320*480 | 480*800 | 720*1280 | 1080*1920 |
dpi | 120 | 160 | 240 | 320 | 480 |
限定符 | ldpi | mdpi | hdpi | xhdpi | xxhdpi |
---|---|---|---|---|---|
dpi | dpi<=120 | 120<dpi<=160 | 160<dpi<=240 | 240<dpi<=320 | 320<dpi<=480 |
由于安卓手机碎片化比较严重,并不一定满足表一,所以手机dpi在限定符的某个区间
如果获取当前手机的屏幕dpi、density等信息?
getResources().getDisplayMetrics();
比如当前手机分辨率1080*1920,尺寸5.5,获取相关信息如下:
metrics.heightPixels = 1920
metrics.widthPixels = 1080
metrics.densityDpi = 480 //dpi值
metrics.density = 3.0 //基准比例,dpi/160
metrics.xdpi = 403.411 //x方向准确的物理像素密度
metrics.ydpi = 403.041 //y方向准确的物理像素密度
metrics.scaledDensity = 3.0
发现x方向的dpi和y方向的dpi和densityDpi不一致,再次说明densityDpi与设备硬件是无关的。
结论
- 屏幕适配的时候一般考虑的两个因素:分辨率和dpi。
- 利用dpi换算dp和px的值(两个公式)
- 使用限定符适配不同dpi的屏幕,不同限定符下dp值的计算
- android开发中使用的dpi的值是不固定的,可以修改的
drawable文件夹下的图片适配:
图片资源的读取规则
当我们使用资源id来去引用一张图片时,Android会使用一些规则来帮我们匹配最适合的图片。什么叫最适合的图片?比如我的手机屏幕密度是xxhdpi,那么drawable-xxhdpi文件夹下的图片就是最适合的图片。因此,当我引用一张图片时,如果drawable-xxhdpi文件夹下有这张图就会优先被使用,在这种情况下,图片是不会被缩放的。但是,如果drawable-xxhdpi文件夹下没有这张图时, 系统就会自动去其它文件夹下找这张图了,优先会去更高密度的文件夹下找这张图片,也就是drawable-xxxhdpi文件夹,然后发现这里也没有android_logo这张图,接下来会尝试再找更高密度的文件夹,发现没有更高密度的了,这个时候会去drawable-nodpi文件夹找这张图,发现也没有,那么就会去更低密度的文件夹下面找,依次是drawable-xhdpi -> drawable-hdpi -> drawable-mdpi -> drawable-ldpi。
android项目资源下的drawable(不带任何限定符)目录默认就是drawable-mdpi的意思
作者:郭霖
链接:http://blog.csdn.net/guolin_blog/article/details/50727753
如果没有在对应的drawable文件夹下找到合适的图片,而是按照资源读取规则使用了其他drawable的图片,则会对图片进行一个缩放,缩放比例和dpi比例一致,见下图:
ldpi | mdpi | hdpi | xhdpi | xxhdpi | |
---|---|---|---|---|---|
dpi | 120 | 160 | 240 | 320 | 480 |
比例 | 3 | 4 | 6 | 8 | 12 |
mdpi:hdpi:xhdpi:xxhdpi=1:1.5:2:3
比如启动icon,Android Studio对应生成的icon如下:
- mipmap-mdpi:48*48
- mipmap-hdpi:72*72
- mipmap-xhdpi:96*96
- mipmap-xxhdpi:144*144
由此可以看出只需要一套图片就可以适配所有的手机(自动缩放的关系),但是图片分辨率要尽可能的高些,以免小图片在高dpi设备上由于放大导致的模糊。
参考文章: