博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
理一理屏幕尺寸那些事
阅读量:7223 次
发布时间:2019-06-29

本文共 8109 字,大约阅读时间需要 27 分钟。

注:本文的目的在于理清楚一些尺寸关系,如果有表述不当,欢迎指出讨论

本文测试屏幕的长宽像素比为1,奇葩屏幕可跟根据比例自行分析


一、科普常识:

0.测试准备

手上有两个真机: oppoA77(1920*1080 5.5英寸)、 oppoR15X(2340*1080 6.4英寸) 、

再加一台模拟器(480*320 3.5英寸)仿OPPO R801
辅助:一台笔记本电脑联想Y480N(768*1366 14英寸) 和一个iPad_Air_2(2048*1536 9.7英寸)


1.按照像素来算引出的问题(反证法):

如果,我说如果一个像素代表n个物理毫米,当n等于1时

那么oppoR15X(2340*1080)相当于23.4*10.8cm,量了一下,大概跟书差不多
OPPO R801(480*320)相当于(4.8*3.2cm),量了一下,差不多跟橡皮一样大

在同一参考系下,玩oppoR15X和OPPO R801,相当于玩一本书和玩橡皮的区别

显然我并没有这样的体验,这只能说明,对于两个不同的手机,它们的n值不同
也就是两个手机:1个物理毫米中所含的像素个数是不同的


2.手机英寸的概念

英寸是衡量手机屏幕的真实大小

我们买手机一般关心的是手机是多少多少英寸的,然后懂行的看看分辨率,那英寸代表什么?
1英寸 = 2.54 厘米: 大概和一元硬币的直径差不多,不信你拿六个硬币排在对角线比一下

由于分辨率确定了长宽比,我们不难算出oppoR15X和OPPO R801的物理宽高

\ 宽px 高px 对角线in 对角线cm 物理宽cm 物理高cm
oppoR15X 1080px 2340px 6.4in 16.256cm 6.81cm 14.76cm
OPPO R801 320px 480px 3.5in 8.89cm 4.93cm 7.40cm

3.屏幕属性的封装

这么多属性,一个一个算也怪累人的,计算器点着也不爽,封装一下吧ScreenInfo.java

/** * 作者:张风捷特烈
* 时间:2018/12/1 0001:8:01
* 邮箱:1981462002@qq.com
* 说明:屏幕尺寸信息 */public class ScreenInfo { public static final float INCH_TO_MM = 25.399999961392f;//英寸转为毫米数 public String name;//设备名称 public float inchC;//英寸 public int pxW;//屏幕宽像素数 public int pxH;//屏幕高像素数 public int pxC;//对角线像素数 public float ppi; public float dpi; public float relW;//实际宽度 public float relH;//实际高度 public float relC;//实际对角线长度 public ScreenInfo() { } public ScreenInfo(String name, float inchC, int pxH, int pxW) { this.name = name; this.inchC = inchC; this.pxW = pxW; this.pxH = pxH; pxC(); ppi(); dpi(); relC(); relW(); relH(); } private int pxC() { pxC = (int) Math.sqrt(pxH * pxH + pxW * pxW); return pxC; } private float ppi() { ppi = pxC() / inchC; return ppi; } private float dpi() { dpi = pxC() / inchC; return dpi; } private float relW() { relW = relC * (pxW * 1.f / pxC()); return relW; } private float relH() { relH = relC * (pxH * 1.f / pxC()); return relH; } private float relC() { relC = inchC * INCH_TO_MM; return relC; } @Override public String toString() { return "ScreenInfo{" + "\nname='" + name + '\'' + "\n, 屏幕尺寸/英寸=" + inchC + "\n, 屏幕横向像素数=" + pxW + "\n, 屏幕纵向像素数=" + pxH + "\n, 屏幕对角线像素数=" + pxC + "\n, ppi=" + ppi + "\n, dpi=" + dpi + "\n, 屏幕对角线物理尺寸/mm=" + relC + "\n, 屏幕横向物理尺寸/mm=" + relW + "\n, 屏幕纵向物理尺寸/mm=" + relH + '}'; }}复制代码

好吧,知道大家不喜欢看数据,于是我自定义了一个View,用ScreenInfo信息画个图示,感觉还蛮好的

三行代码就能画一个手机信息图,也不是很难,有兴趣的可以看看源码,或自己画画
我是按照物理尺寸画的,所以现实中它们的屏幕相对大小就是这样的!

如果你想玩,其他的屏幕也可以试试:只要知道分辨率和多少英寸


4.密度:
什么是密度?----紧密程度?上学的时候应该听过线密度,面密度和体密度、或者人口密度吧。比如一个市的人口密度:合肥市面积为11445.1平方公里,人口为779万,人口密度为680.6人/平方公里也就是合肥市平均 1平方公里 有680.6人复制代码
现在把屏幕当做土地,把像素点当做人,这些人一个一个有秩序地排着 那么OPPOR15X中1mm的长度排多少个像素,显而易见:2577px/163mm = 15.809...  取个整 15.8那么 1 平方毫米能容下几个像素呢? 15.8*15.8 = 249.64个/mm^2  约250个/mm^2那么OPPOR801中1mm的长度排多少个像素,显而易见:576px/163mm =  6.471...  取个整 6.5那么 1 平方毫米能容下几个像素呢? 6.5*6.5 = 42.25个/mm^2  约42个/mm^2相当于在一片等大的土地上,一块占了250个人,一块占了42个人,神奇的是两边都把这块地占满了于是真相(得出的结论)只有一个:两块土地上一块是小人,一块是巨人  复制代码

现在把物理尺寸:1mm的屏幕放大

记得小时候的手机肉眼就能看到一点一点的像素,就是因为1mm里的像素点少,相对而言一粒像素就大

现在的手机可是瞅不出来像素了


5.ppi与dip

现在我们手上的信息还蛮多的,这些信息有什么用?

ppi(Pixel Per Inch),即每英寸的像素。
我们刚才好像算了每毫米的像素数,那每英寸的像素数能难倒你吗?OPPO-R15X 的 ppi : 2577px/6.4in = 402.65625 px/in   约402.6ppiOPPO-A77 的 ppi : 2202px/5.5in = 400.363... px/in   约400.4ppiOPPO-R801 的 ppi : 576px/3.5in = 164.571... px/in   约164.6ppi复制代码
ppi形象一点的比喻:

一个一元硬币直径约1 in,现在让一元硬币(包括背景)等大显示在三个手机上:

OPPO-R15X需要用:402*402=161604 个像素点
OPPO-A77需要用:400*400=160000 个像素点
OPPO-R15X需要用:164*164=26896 个像素点
我们知道像素组成了显示的图片,也就是说用161604个点和26896个点组成相同的画面
那么26896的那个看起来效果自然要比161604的差很多,161604更加紧密,所以视觉感好

来分析一下笔记本电脑:

ppi=1567/14=111.928...,也就是 1 in 里有112个点,1 in = 25.4mm

那说明一个像素的大小是 25.4 / 112 = 0.226mm ,人眼可视长度是0.1mm,所以你近些看可以看到颗粒


dpi(Dot Per Inch),即每英寸的点数。
dpi又是什么鬼,点数又是什么鬼?---dpi称为打印精度打印机将[彩色液体油墨]经喷嘴变成细小微粒喷到印纸上,一个颗粒代表1点  dpi的意思是每英寸墨滴点数,比如300dpi的意思就是每英寸墨滴的个数为300用300个点表示一个硬币,和72个点表示一个硬币,可想而知300的更加精细大学时做要打印的ps产品效果图都要把图片的dpi调到300以上,因为大幅的海报需要细致的像素表达普通的web图片只要求72dpi就够了,因为只是显示在屏幕上而言 复制代码
ppi和dpi在Android
Android又不是打印机,dpi和ppi等价,都是表示 1 in长度对应的px数  也许谷歌更倾向于用`点(dot)` 来表述屏幕像素,所以采用dpi的说法而不是ppi复制代码

二、谁动了我的图片尺寸?

1.我的250*200的图片画出来怎么尺寸不对?----Q1

实验图片:250*200,300dpi,res\mipmap-xhdpi\wy_250px_200px_300dpi.jpg

实验图片:250*200,72dpi,res\mipmap-xhdpi\wy_250px_200px_72dpi.jpg

这是挺纠结的一个问题,我预想的是在小手机上图片250px应该会很大

为什么并不是我所预料的那样?而且自定义的图片dpi被无视了?----Q2


2.我怀着满心的疑问将图片拷贝到drawable里

实验图片:250*200,72dpi,res\drawable\wy_250px_200px_72dpi.jpg

实验图片:250*200,300dpi,res\drawable\wy_250px_200px_300dpi.jpg

貌似对dpi还是免疫,而且OPPO-R15X图片按比例放大了,分别弹了一个metric.density,一个3,一个1

哥就想都显示250*200为什么这么难?----Q3


3.怀着疑问,分别将图片在mipmap各个文件夹放一遍

测试结果如下,并画了一张高度变动的简单示意图

可以看出:1.OPPO-R15X在xxh的时候显示原图,OPPO-R801在m的时候显示原图2.每种情况下OPPO-R15X的高度总是OPPO-R801的3倍结论:OPPO-R15X自身dpi(ppi)为402,被圈入了xxh的领域,OPPO-R801自身dpi(ppi)为164,被圈入了m的领域xxh对应的dpi/m对应的dpi = 3复制代码

Q1:谁动了我的图片尺寸---mipmap的不同文件夹,Android会区分对待Q2:而且自定义的图片dpi被无视了?----图片自身的dpi对屏幕设备的显示并没有效果,只对打印有影响Q3:哥就想都显示250*200为什么这么难?---- 难! 但是也没有这个必要,你非怎么想,在所有的mipmap文件夹都放一张图,然后所有手机会显示250*200,不过有人打你不关我事...  复制代码

4.获取不在mipmap里的图片会怎么样?

这个问题问的好,代码测试走一波

不出所料,从文件读取的图片,没走mipmap,所以原像素显示

总结:mipmap会根据图片的文件夹位置对图片在不同density设备上进行不同的缩放,也就是"自动适配"

只限获取图片时或使用时warp_content


三、看看那些尺寸

1.dp:

想必大家这个方法都用过

protected float dp(float dp) {    return TypedValue.applyDimension(    TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());}复制代码

来看看它到底干了什么:applyDimension

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;//将值*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;}复制代码

代码追踪:
--> getResources().getDisplayMetrics()-->[android.content.res.Resources#getDisplayMetrics]public DisplayMetrics getDisplayMetrics() {    return mResourcesImpl.getDisplayMetrics();}-->[android.content.res.ResourcesImpl#getDisplayMetrics]DisplayMetrics getDisplayMetrics() {    if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels            + "x" + mMetrics.heightPixels + " " + mMetrics.density);    return mMetrics;}-->[现在要看: mMetrics.density被赋值时]if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {    mMetrics.densityDpi = mConfiguration.densityDpi;    mMetrics.density =            mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;}搜索到:mConfiguration.densityDpi = DisplayMetrics.DENSITY_DEVICE;复制代码

我们被奉为灵丹妙药的dp只不过获取了DisplayMetrics.DENSITY_DEVICE,再乘以0.00625(即除以160)

而且这个DisplayMetrics.DENSITY_DEVICE也并非屏幕真正的dpi(ppi),400的,402的都算是480,
所以dp的计算方式也是一个满足大众需要的约值,虽然有一定的效果,但并不能完美适配。


真的有完美的适配吗?

除非你能让长宽是100*180的纸片能够恰好装满长宽是100*200盒子而且没有变形

或者让所有的安卓手机厂家生产相同比例的手机,否则无论怎么配会有瑕疵,
鱼和熊掌不可兼得 ,但舍生和取义之间还有平常地活着(尽管并不完美)

我曾经有想过,为什么手机不是圆形的,如果是圆形的就不需要适配了,永远等比例  也许兜里放着占地方吧,或者看电影,可用面积会比较少...感觉好可惜复制代码

文字单位:sp
-->[android.util.TypedValue#applyDimension] case COMPLEX_UNIT_SP:     return value * metrics.scaledDensity;-->[android.content.res.ResourcesImpl#updateConfiguration] mMetrics.scaledDensity = mMetrics.density *    (mConfiguration.fontScale != 0 ? mConfiguration.fontScale : 1.0f);    //现在焦点移到:mConfiguration.fontScale != 0//如果是假的,那就和mMetrics.density的值相同,否则是mConfiguration.fontScale复制代码

其中configuration.fontScale是根据系统字号改变的,默认是1,所以会遇到dp和sp混用无影响的情况。但,一旦用户改变了系统字号,有一定的缩放量,dp的为sp就原形毕露了,所以字体还是乖乖用sp,别没事找事。


关于适配

个人觉得只要多用控件之间进行尺寸依赖关联,也就是约束布局

dp虽然不是灵丹妙药,但是也能治病救人,所以药不能停,dp不能丢
match_parent是好东西,要懂得合理运用
注意左侧和下侧,尽量用父去约束,不然跑出去了……可是大忌 尽量避免使用非常大的dp(200+),可通过控件间相对位置将过大的dp约束,因为数值越大不同手机的差异性越明显。


后记:捷文规范

1.本文成长记录及勘误表
项目源码 日期 备注
V0.1--github 2018-12-4
2.更多关于我
笔名 QQ 微信 爱好
张风捷特烈 1981462002 zdl1994328 语言
3.声明

1----本文由张风捷特烈原创,转载请注明

2----欢迎广大编程爱好者共同交流
3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
4----看到这里,我在此感谢你的喜欢与支持


你可能感兴趣的文章
数字货币交易系统火爆的背后是政策的大力支持
查看>>
gulp与webpack的区别
查看>>
ORA-12547:TNS:lost contact 问题分析思路
查看>>
解决firefox疯狂读硬盘的问题
查看>>
清华产业十大创新项目评选 新华三H3Cloud OS夺冠
查看>>
事务操作的统计,TPS的计算,隔离级别的读提交
查看>>
转贴:Ms Sql Server 2008 集成 SP1的方法!!!
查看>>
Memcache监控工具 -- memcache-top
查看>>
3-9 读写缓存流 ——BufferedStream类
查看>>
linux head
查看>>
Oracle osw监控工具的使用示例
查看>>
在Spring中整合JUnit单元测试
查看>>
Namenode双机热备之Pacemaker
查看>>
Xcode调试断点不停止解决方案!
查看>>
CentOS6.6+Puppet3.7.4分布式部署Nagios监控系统
查看>>
SQL Server 2008 存储结构之DCM、BCM
查看>>
asp.net2005里给控件重命名,提示“目录名无效”怎么解决
查看>>
Redis源码解析--Replication
查看>>
Java的多进程运行模式分析
查看>>
百度面试题:求绝对值最小的数
查看>>