雜篇:理一理屏幕尺寸那些事

注:本文的目的在於理清楚一些尺寸關係,若是有表述不當,歡迎指出討論

本文測試屏幕的長寬像素比爲1,奇葩屏幕可跟根據比例自行分析


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英寸)java

測試資源.png


1.按照像素來算引出的問題(反證法):

若是,我說若是一個像素表明n個物理毫米,當n等於1時
那麼oppoR15X(2340*1080)至關於23.4*10.8cm,量了一下,大概跟書差很少
OPPO R801(480*320)至關於(4.8*3.2cm),量了一下,差很少跟橡皮同樣大android

像素級截圖比較.jpg

在同一參考系下,玩oppoR15X和OPPO R801,至關於玩一本書和玩橡皮的區別
顯然我並無這樣的體驗,這隻能說明,對於兩個不一樣的手機,它們的n值不一樣
也就是兩個手機:1個物理毫米中所含的像素個數是不一樣的git


2.手機英寸的概念

英寸是衡量手機屏幕的真實大小
咱們買手機通常關心的是手機是多少多少英寸的,而後懂行的看看分辨率,那英寸表明什麼?
1英寸 = 2.54 釐米: 大概和一元硬幣的直徑差很少,不信你拿六個硬幣排在對角線比一下github

英寸.png

因爲分辨率肯定了長寬比,咱們不難算出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

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 + '}'; } } 複製代碼

尺寸解析.png

好吧,知道你們不喜歡看數據,因而我自定義了一個View,用ScreenInfo信息畫個圖示,感受還蠻好的
三行代碼就能畫一個手機信息圖,也不是很難,有興趣的能夠看看源碼,或本身畫畫
我是按照物理尺寸畫的,因此現實中它們的屏幕相對大小就是這樣的!bash

屏幕尺寸.png

若是你想玩,其餘的屏幕也能夠試試:只要知道分辨率和多少英寸微信

查看其餘屏幕尺寸.png


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的屏幕放大app

1px.png

記得小時候的手機肉眼就能看到一點一點的像素,就是由於1mm裏的像素點少,相對而言一粒像素就大
如今的手機但是瞅不出來像素了ide


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什麼意思.png

來分析一下筆記本電腦:

ppi=1567/14=111.928...,也就是 1 in 裏有112個點,1 in = 25.4mm
那說明一個像素的大小是 25.4 / 112 = 0.226mm ,人眼可視長度是0.1mm,因此你近些看能夠看到顆粒

筆記本屏幕分析.png


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
複製代碼

2、誰動了個人圖片尺寸?

測試圖片.png

1.個人250*200的圖片畫出來怎麼尺寸不對?----Q1

實驗圖片:250*200,300dpi,res\mipmap-xhdpi\wy_250px_200px_300dpi.jpg

mipmap_xhdpi_250px_200px_300dpi.png

實驗圖片:250*200,72dpi,res\mipmap-xhdpi\wy_250px_200px_72dpi.jpg

mipmap_xhdpi_250px_200px_72dpi.png

這是挺糾結的一個問題,我預想的是在小手機上圖片250px應該會很大
爲何並非我所預料的那樣?並且自定義的圖片dpi被無視了?----Q2


2.我懷着滿心的疑問將圖片拷貝到drawable裏

實驗圖片:250*200,72dpi,res\drawable\wy_250px_200px_72dpi.jpg

drawable_250px_200px_72dpi.png

實驗圖片:250*200,300dpi,res\drawable\wy_250px_200px_300dpi.jpg

drawable_250px_200px_300dpi.png

貌似對dpi仍是免疫,並且OPPO-R15X圖片按比例放大了,分別彈了一個metric.density,一個3,一個1
哥就想都顯示250*200爲何這麼難?----Q3


3.懷着疑問,分別將圖片在mipmap各個文件夾放一遍

測試結果以下,並畫了一張高度變更的簡單示意圖

高度分析.png

能夠看出:
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
複製代碼

數據.png

Q1:誰動了個人圖片尺寸
---mipmap的不一樣文件夾,Android會區分對待

Q2:並且自定義的圖片dpi被無視了?
----圖片自身的dpi對屏幕設備的顯示並無效果,只對打印有影響

Q3:哥就想都顯示250*200爲何這麼難?
---- 難! 可是也沒有這個必要,你非怎麼想,在全部的mipmap文件夾都放一張圖,
而後全部手機會顯示250*200,不過有人打你不關我事...  
複製代碼

4.獲取不在mipmap裏的圖片會怎麼樣?

這個問題問的好,代碼測試走一波
不出所料,從文件讀取的圖片,沒走mipmap,因此原像素顯示

load_form_file.png

總結:mipmap會根據圖片的文件夾位置對圖片在不一樣density設備上進行不一樣的縮放,也就是"自動適配"
只限獲取圖片時或使用時warp_content


3、看看那些尺寸

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;
}
複製代碼

metrics.png

代碼追蹤:
--> 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;
複製代碼

mMetrics.density.png

咱們被奉爲靈丹妙藥的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----看到這裏,我在此感謝你的喜歡與支持


icon_wx_200.png
相關文章
相關標籤/搜索