理一理屏幕尺寸那些事

栏目: IOS · Android · 发布时间: 6年前

内容简介:手上有两个真机: oppoA77(再加一台模拟器(辅助:一台笔记本电脑联想Y480N(

手上有两个真机: 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

/**
 * 作者:张风捷特烈<br/>
 * 时间:2018/12/1 0001:8:01<br/>
 * 邮箱:1981462002@qq.com<br/>
 * 说明:屏幕尺寸信息
 */
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的长度排多少个像素,显而易见:2577px/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.6ppi
OPPO-A77 的 ppi : 2202px/5.5in = 400.363... px/in   约400.4ppi
OPPO-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 语言
我的github 我的简书 我的掘金 个人网站

3.声明

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

2----欢迎广大编程爱好者共同交流

3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正

4----看到这里,我在此感谢你的喜欢与支持

理一理屏幕尺寸那些事

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

琢石成器

琢石成器

罗云彬 / 电子工业出版社 / 2009-6 / 89.00元

Windows环境下32位汇编语言是一种全新的编程语言。它使用与C++语言相同的API接口,不仅可以开发出大型的软件,而且是了解操作系统运行细节的最佳方式。 本书从编写应用程序的角度,从“Hello,World!”这个简单的例子开始到编写多线程、注册表和网络通信等复杂的程序,通过70多个实例逐步深入Win32汇编语言编程的方方面面。 本书作者罗云彬拥有十余年汇编语言编程经验,是汇编编程......一起来看看 《琢石成器》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

html转js在线工具
html转js在线工具

html转js在线工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换