160,240,320,480,
TODO: px 像素,dip,dp,dpi,这几个的概念。适配。
1dp = n个像素? = dpi/160 *1dp = 400/160 = 2.5像素。所以一个1dp在不同手机上,显示像素不一样。
1.1 常用单位
px像素:
dp=dip: Density independent pixels ,设备无关像素。
dpi:dots per inch , 直接来说就是一英寸多少个像素点。常见取值 120,160,240。我一般称作像素密度,简称密度.
density : 直接翻译的话貌似叫 密度。常见取值 1.5 , 1.0 。和标准dpi的比例(160px/inc)
分辨率 : 横纵2个方向的像素点的数量,常见取值 480X800 ,320X480
屏幕尺寸: 屏幕对角线的长度。电脑电视同理。
屏幕比例的问题。因为只确定了对角线长,2边长度还不一定。所以有了4:3、16:9这种,这样就可以算出屏幕边长了。
1.2 在android里面,获取一个窗口的metrics
metrics.density; // 就是我们常说的dpi。
metrics.densityDpi; // 其实是 DPI / (160像素/英寸) 后得到的值。
DPI本身的单位也是 像素/英寸,所以density其实是没单位的,他就是一个比例值。
而dpi的单位是 像素/英寸,比较符合物理上面的密度定义,密度不都是单位度量的值么,所以我更喜欢把dpi叫像素密度,简称密度,density还是就叫density。
densityDpi:240; density:1.5
getResources().getDisplayMetrics().densityDpi 就是屏幕密度。
getResources().getDisplayMetrics().density 也可以理解为1dip相当于多少个px啦。
上面的dpi是240,1dp = 1.5px。
drawable目录对应的最大dpi:
ldpi(120 DPI),mdpi(160 DPI),hdpi(240 DPI),xhdpi(320 DPI),xxhdpi(480 DPI),xxxhdpi(640 DPI)
0.75 1 1.5 2 3 4
3/0.75 = 4;
1.3 放在不同drawable文件夹的区别。
配置:模拟器(10801920 xxhdpi=480dpi), 图片(7201280 xxhdpi)
图片放置ldpi(4倍关系): 图片长=720*(16/4)=2880 图片宽 = 1280 *(16/4) = 5120 scale=480/120=4
图片放置mdpi(3倍关系): 图片长 = 720 *(12/4)= 2160 图片宽 = 1280 *(12/4) = 3840 scale=480/160=3
图片放置hdpi(2倍关系): 图片长 = 720 *(8/4)= 1440 图片宽 = 1280 *(8/4) = 2560 scale=480/240=2
图片放置xhdpi(1.5倍关系):图片长 = 720 *(6/4)= 1080 图片宽 = 1280 *(6/4) = 1920 scale=480/320=1.5
图片放置xxhdpi(1倍关系):图片长 = 720 *(4/4)= 720 图片宽 = 1280 *(4/4) = 1280 scale=1 (无倍数关系,不会对图像进行放缩,保持原始大小)
图片放置xxxhdpi(0.75倍关系):图片长 = 720 *(3/4)=540 图片宽 = 1280 *(3/4)= 960 scale=480/640=0.75
nohdpi(无缩放)
drawable和drawable-mdpi是一样的大小,是因为drawable-mdpi是系统默认的像素密度,其他像素密度都以它为基数,
当只在drawable中存在图片时,如果使用该图片,那么将按照drawable-mdpi的放缩比例进行放缩。
例如,当前设备的dpi是480(即xxhdpi),那么对于存放于mdpi目录中的图片会被放大三倍。
对于很多设备,其dpi并不刚好是六种通用密度最大dpi,这种情况下,图片的缩放倍数如何计算呢?
缩放倍数(缩放因子)计算方法:对于任意设备,各drawable-[density]目录下的图片放大倍数的计算公式
公式:【scale = 设备dpi / 图片所在Drawable目录对应最大dpi】。
那么,图片的实现显示尺寸通过图片尺寸乘以缩放倍数就可以得到了。
1.4 单位间转换
- 计算dpi
比如一个机器,屏幕4寸,分辨率480X800,他的dpi能算么。
dpi = 开根号(480480+800800)/4。
因为不知道边长,肯定不能分开算,4是对角线长度,那直接用勾股定理算对角线像素,除以4,算出来大概是 dpi = 233 像素/英寸。
那么density就是 (233 px/inch)/(160 px/inch)=1.46 左右, density 是没有单位的。
顺带说下,android默认的只有3个dpi,low、medium和high,对应 120、160、240.
其中的default就是160。
- 计算 dp 与 px
我们写布局的时候,肯定还是要知道1个dp到底有多少px的。
换算公式如下: dp = (DPI/(160像素/英寸))px = density px
注意,这里都是带单位的。px是单位,dp是单位,density没单位。
为了方便,假设dpi是240 像素/英寸 , 那么density就是1.5
那么就是 dp=1.5px ,注意这是带了单位的,也就是 设备无关像素 = density 像素
那么转换为数值计算的话,应该是下面这个式子
PX = density * DP
也就是
像素值 = density * 设备无关像素值 ,请注意这里有个值字。
为啥 标准dpi = 160
(1)Android Design [1] 里把主流设备的 dpi 归成了四个档次,120 dpi、160 dpi、240 dpi、320 dpi
实际开发当中,我们经常需要对这几个尺寸进行相互转换(比如先在某个分辨率下完成设计,然后缩放到其他尺寸微调后输出),
一般按照 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.
(2)这个在Google的官方文档中有给出了解释,因为第一款Android设备(HTC的T-Mobile G1)是属于160dpi的。屏幕尺寸:屏幕的对角线长度,一般讲的大小单位都是英寸。
比如iPhone5S的屏幕尺寸是4英寸。Samsung Note3是5.7英寸。像素:屏幕上每个小点。
分辨率Resolution:屏幕上垂直方向和水平方向上的像素个数。
比如iPhone5S的分辨率是1136640;Samsung Note3的分辨率是19201080;dpi(dot per inch): 每英寸的像素数,也叫做屏幕密度。这个值越大,屏幕就越清晰。
比如iPhone5S的dpi是326; Samsung Note3 的dpi是386。dip(Density independent pixel): 指的是抽象意义上的像素。跟设备的屏幕密度有关系。是Android里的一个单位,dip和dp是一样的。
就是说在160dpi的屏幕上,1dip=1px。
它跟屏幕密度有关,如果屏幕密度大,1dip代表的px就多,比如在320dpi的屏幕上,1dip=2px。
- 为什么我们在布局的时候最好要用dip,不要用px?
在着很多不同屏幕密度的手机,屏幕密度是什么?就是dpi,就是单位长度里的像素数量。
如果这些手机的尺寸一样,屏幕密度相差很大,那么是不是说一个手机水平方向上像素很少,另一个手机水平方向上像素很多?
那我们画同样pix数量的时候,它显示的长度不就会不一样了?
两种概念:
- 图片和手机配置都固定的情况下 图片放置到不同文件夹(上面介绍的这种);
- 图片放置固定文件夹 多分辨率的手机加载(常用场景);
简述第2中概念:假如 图片固定放到xxhdp文件夹下
1、你的手机分辨率是1920 * 1080那么图片保持原始大小加载;
2、手机分辨率是大于1920 * 1080,则会将图片等比放大 加载;
3、手机分辨率是大于1920 * 1080,则会将图片等比缩小 加载;
总结:
当图片放置在不同drawable文件夹中,且只有这一张图片时,运行设备会根据自身的屏幕密度,对图片进行放缩,放缩比例符合前面图上的规则
图片文件的大小与在内存中占用的大小没关系,内存中实际占用大小与图片分辨率、像素显示参数有关
所以,在一个App里面使用一套UI理论上应该是没有问题的,但是要注意:
最好使用较高分辨率的切图,并且放置在正确的drawable文件夹中,比如按照xxhdpi的分辨率进行切图,放置在drawable-xxhdpi中
对于可以使用.9格式的图片,最好使用.9,减少资源大小
如果有条件,最好提供多套UI切图。如果只有一套切图,系统需要对图片进行压缩,会进行大量运算,影响设备性能。同时,在某些情况下,系统对图片的压缩会可能会出现锯齿,造成信息的丢失
如果是多套切图的话,最好不要直接用工具按照比例放缩,这样小图标会丢失一些细节。当然,这部分是美工来做的,可以让她参考这篇文章利用PS CS6的新功能保持ICON细节饱满完美
思考一下,如果把一个本来应该放在drawable-xxhdpi里面的图片放在了drawable文件夹中会出现什么问题呢?
明明是(4/4)变成了(12/4) 导致 在xxhdpi设备上,图片会被放大3倍,图片内存占用就会变为原来的9(3*3)倍!
2.图片加载顺序
比如在一个中等分辨率的手机上,Android就会选择drawable-mdpi文件夹下的图片,
- 文件夹下有这张图就会优先被使用,在这种情况下,图片是不会被缩放的;
- 但是如果没有在drawable-mdpi的文件夹下找到相应图片的话,Android系统会首先从更高一级的drawable-hdpi文件夹中查找,如果找到图片资源就进行缩放处理,显示在屏幕上;
- 如果drawable-hdpi文件夹下也没有的话,就依次往drawable-xhdpi文件夹、drawable-xxhdpi文件夹、drawable-xxxhdpi文件夹、drawable-nodpi;
- 如果更高密度的文件夹里都没有找到,就往更低密度的文件夹里寻找,drawable-ldpi文件夹下查找;
- 如果都没找到,最终会在默认的drawable文件夹中寻找,如果默认的drawable文件夹中也没有那就会报错啦。(前提是把一张图片做成很多不同的分辨率放在各个对应密度的drawable文件夹下)
举个例子,假如当前设备的dpi是320,系统会优先去drawable-xhdpi目录查找,如果找不到,会依次查找xxhdpi → xxxhdpi → hdpi → mdpi → ldpi。
对于不存在的drawable-[density]目录直接跳过,中间任一目录查找到资源,则停止本次查找。
float xdpi = getResources().getDisplayMetrics().xdpi;
知道设备的dpi后就知道设备首先会在哪个drawable文件夹下去寻找了:dpi范围密度对应范围
设备密度 适配资源文件密度 放大倍数
0dpi ~ 120dpi ldpi 0.75
120dpi ~ 160dpi mdpi(基线BaseLine) 1.0
160dpi ~ 240dpi hdpi 1.5
240dpi ~ 320dpi xhdpi 2.0
320dpi ~ 480dpi xxhdpi 3.0
480dpi ~ 640dpi xxxhdpi 4.0
总体匹配规则就是这样:
- 如果图片所在目录dpi低于匹配目录,那么该图片被认为是为低密度设备需要的,现在要显示在高密度设备上,图片会被放大。
- 如果图片所在目录dpi高于匹配目录,那么该图片被认为是为高密度设备需要的,现在要显示在低密度设备上,图片会被缩小。
- 如果图片所在目录为drawable-nodpi,则无论设备dpi为多少,保留原图片大小,不进行缩放。
例如,当前设备的dpi是480(即xxhdpi),那么对于存放于mdpi目录中的图片会被放大三倍。
对于很多设备,其dpi并不刚好是六种通用密度最大dpi,这种情况下,图片的缩放倍数如何计算呢?
scale = 设备dpi/ 图片所在Drawable目录对应最大dpi。
3.dpi计算方式:
密度(dpi,dots per inch;或PPI,pixels per inch)。
从英文顾名思义,就是每英寸的像素点数,数值越高当然显示越细腻。
假如我们知道一部手机的分辨率是1080×1920,屏幕大小是5英寸,你能否算出此屏幕的密度呢?
哈哈,中学的勾股定理派上用场啦!通过宽1080和高1920,根据勾股定理,
我们得出对角线的像素数大约是2203,那么用2203除以5就是此屏幕的密度了,计算结果是440。
440dpi的屏幕已经相当细腻了。