内容简介:手上有两个真机: 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.更多关于我
笔名 | 微信 | 爱好 | |
---|---|---|---|
张风捷特烈 | 1981462002 | zdl1994328 | 语言 |
我的github | 我的简书 | 我的掘金 | 个人网站 |
3.声明
1----本文由张风捷特烈原创,转载请注明
2----欢迎广大编程爱好者共同交流
3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
4----看到这里,我在此感谢你的喜欢与支持
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- flutter 屏幕尺寸适配 字体大小适配
- Flutter之支持不同的屏幕尺寸和方向
- 手机屏幕尺寸测试――手机的实际显示页面的宽度
- XBOOT尺寸裁剪
- CSS中的尺寸单位
- iphone – UIBarButtonItem尺寸不同
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。