注:本文的目的在於理清楚一些尺寸關係,若是有表述不當,歡迎指出討論
本文測試屏幕的長寬像素比爲1,奇葩屏幕可跟根據比例自行分析
手上有兩個真機: 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英寸
)java
若是
,我說若是
一個像素表明n個物理毫米,當n等於1時
那麼oppoR15X(2340*1080
)至關於23.4*10.8cm
,量了一下,大概跟書差很少
OPPO R801(480*320
)至關於(4.8*3.2cm
),量了一下,差很少跟橡皮同樣大android
在同一參考系下,玩oppoR15X和OPPO R801,至關於玩一本書和玩橡皮的區別
顯然我並無這樣的體驗,這隻能說明,對於兩個不一樣的手機,它們的n值不一樣
也就是兩個手機:1個物理毫米中所含的像素個數是不一樣的
git
英寸是衡量手機屏幕的真實大小
咱們買手機通常關心的是手機是多少多少英寸的,而後懂行的看看分辨率,那英寸表明什麼?
1英寸 = 2.54 釐米
: 大概和一元硬幣的直徑差很少,不信你拿六個硬幣排在對角線比一下github
因爲分辨率肯定了長寬比,咱們不難算出oppoR15X和OPPO R801的物理寬高web
\ | 寬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 |
這麼多屬性,一個一個算也怪累人的,計算器點着也不爽,封裝一下吧
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信息畫個圖示,感受還蠻好的
三行代碼就能畫一個手機信息圖,也不是很難,有興趣的能夠看看源碼,或本身畫畫
我是按照物理尺寸畫的,因此現實中它們的屏幕
相對大小就是這樣的!bash
若是你想玩,其餘的屏幕也能夠試試:只要知道分辨率和多少英寸微信
什麼是密度?----緊密程度?
上學的時候應該聽過線密度,面密度和體密度、或者人口密度吧。
好比一個市的人口密度:合肥市面積爲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的屏幕放大app
記得小時候的手機肉眼就能看到一點一點的像素,就是由於1mm裏的像素點少,相對而言一粒像素就大
如今的手機但是瞅不出來像素了ide
如今咱們手上的信息還蠻多的,這些信息有什麼用?
咱們剛纔好像算了每毫米的像素數,那每英寸的像素數能難倒你嗎?
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
複製代碼
一個一元硬幣直徑約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又是什麼鬼,點數又是什麼鬼?---dpi稱爲打印精度
打印機將[彩色液體油墨]經噴嘴變成細小微粒噴到印紙上,一個顆粒表明1點
dpi的意思是每英寸墨滴點數,好比300dpi的意思就是每英寸墨滴的個數爲300
用300個點表示一個硬幣,和72個點表示一個硬幣,可想而知300的更加精細
大學時作要打印的ps產品效果圖都要把圖片的dpi調到300以上,由於大幅的海報須要細緻的像素表達
普通的web圖片只要求72dpi就夠了,由於只是顯示在屏幕上而言
複製代碼
Android又不是打印機,dpi和ppi等價,都是表示 1 in長度對應的px數
也許谷歌更傾向於用`點(dot)` 來表述屏幕像素,因此採用dpi的說法而不是ppi
複製代碼
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
實驗圖片:
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
測試結果以下,並畫了一張高度變更的簡單示意圖
能夠看出:
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,不過有人打你不關我事...
複製代碼
這個問題問的好,代碼測試走一波
不出所料,從文件讀取的圖片,沒走mipmap,因此原像素顯示
總結:mipmap會根據圖片的文件夾位置對圖片在不一樣density設備上進行不一樣的縮放,也就是"自動適配"
只限獲取圖片時或使用時warp_content
想必你們這個方法都用過
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盒子
並且沒有變形
或者讓全部的安卓手機廠家生產相同比例的手機,不然不管怎麼配會有瑕疵,
魚和熊掌不可兼得
,但捨生和取義之間還有日常地活着
(儘管並不完美)
我曾經有想過,爲何手機不是圓形的,若是是圓形的就不須要適配了,永遠等比例
也許兜裏放着佔地方吧,或者看電影,可用面積會比較少...感受好惋惜
複製代碼
-->[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約束,由於數值越大不一樣手機的差別性越明顯。
項目源碼 | 日期 | 備註 |
---|---|---|
V0.1--github | 2018-12-4 | 理一理屏幕尺寸那些事 |
筆名 | 微信 | 愛好 | |
---|---|---|---|
張風捷特烈 | 1981462002 | zdl1994328 | 語言 |
個人github | 個人簡書 | 個人掘金 | 我的網站 |
1----本文由張風捷特烈原創,轉載請註明
2----歡迎廣大編程愛好者共同交流
3----我的能力有限,若有不正之處歡迎你們批評指證,一定虛心改正
4----看到這裏,我在此感謝你的喜歡與支持