1. 程式人生 > >螢幕適配:dp、px、ppi、sp、手機尺寸和解析度之間的關係

螢幕適配:dp、px、ppi、sp、手機尺寸和解析度之間的關係

DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int screenWidthPx = dm.widthPixels;
int screenHeighPx = dm.heightPixels;
int virtualKeyHeight = 0;
Resources res = getResources();
int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0)
    virtualKeyHeight = res.getDimensionPixelSize(resourceId);
float density = getResources().getDisplayMetrics().density;
int screenWidthDp = (int) (screenWidthPx / density + 0.5f);
int screenHeighDp = (int) ((screenHeighPx + virtualKeyHeight) / density + 0.5f);
Log.i(TAG, "螢幕寬:" + screenWidthPx + "px,螢幕高:" + screenHeighPx + "px,虛擬鍵高:" + virtualKeyHeight + "px");
Log.i(TAG, "螢幕寬:" + screenWidthDp + "dp,螢幕高:" + screenHeighDp + "dp,density:" + density);
分別在三款手機上執行出的結果:
(1)榮耀8:主屏尺寸:5.2英寸。主屏解析度:1920x1080畫素
螢幕寬:1080px,螢幕高:1794px,虛擬鍵高:126px
螢幕寬:360dp,螢幕高:640dp,density:3.0
(2)E2:主屏尺寸:5.2英寸。主屏解析度:1280x720畫素
螢幕寬:720px,螢幕高:1184px,虛擬鍵高:96px
螢幕寬:360dp,螢幕高:640dp,density:2.0
(3)S9:主屏尺寸:英寸。主屏解析度:1440x720畫素
螢幕寬:720px,螢幕高:1344px,虛擬鍵高:96px

螢幕寬:360dp,螢幕高:720dp,density:2.0

(4):主屏尺寸:英寸。主屏解析度:1280x640畫素
螢幕寬:640px,螢幕高:1184px,虛擬鍵高:96px
螢幕寬:320dp,螢幕高:640dp,density:2.0


    手機螢幕的尺寸用螢幕顯示區對角線的尺寸表示,一般用英寸作為單位。1英寸(in)=2.54    釐米(cm)。

    px其實所有的畫面都是由一個個的小點組成的,這一個個的小點就稱之為畫素。 一塊方形的螢幕橫向有多少個點,豎向有多少個點,相乘之後的數值就是這塊螢幕的畫素。

    PPI = Pixels per inch,每英寸上的畫素數,即 "畫素密度"
    xhdpi: 2.0
    hdpi: 1.5
    mdpi: 1.0 (baseline)
    ldpi: 0.75
    Android系統定義了四種畫素密度:低(120dpi)、中(160dpi)、高(240dpi)和超高(320dpi),它們對應的dp到px的係數分別為0.75、1、1.5和2(該係數乘dp長度即畫素數)。例如介面上有一個長度為“80dp”的圖片,那麼它在240dpi的手機上實際顯示為80x1.5=120px,在320dpi的手機上實際顯示為80x2=160px。如果你拿這兩部手機放在一起對比,會發現這個圖片的物理尺寸一樣大(120px除以240px/in結果為0.5in即0.5英寸,160px除以320px/in也是0.5英寸),這就是使用dp作為單位的效果。橫向和縱向的每英寸畫素數量值相同,因為大部分手機螢幕使用正方形的畫素點。

    dip與dp完全相同,只是名字不同而已。在早期的Android版本里多使用dip,後來為了與sp統一就建議使用dp這個名字了。

    假設手機螢幕寬度是screenWidthIn英寸,手機螢幕寬有screenWidthPx個畫素點,那麼畫素密度ppi為screenWidthPx  / screenWidthIn,所以手機螢幕寬的總dp值是160 x screenWidthPx / ppi即screenWidthIn x 160 。所以螢幕寬2英寸的手機寬320dp,1dp = 1/160英寸,以此類推。

    dp x ppi / 160 = px    ( ppi / 160即上面程式碼的density值,表示1dp有density個px )。

    sp x ppi / 160 = px

   

      按照畫素密度等於每英寸的畫素數的演算法,將1280的平方和720的平方之和開方後,再除以5.2英寸,結果約等於282.4,並非density:2.0乘以160即320的結果。所以一般手機程式碼算出來的結果會是2.0x160、1.75x160、1.5x160、1x160等之間的數,不是精確的每英寸畫素數。

    解析度為1280x720畫素(螢幕寬:360dp)的手機,可通過 adb shell wm size 640x1280 命令,改成了螢幕寬:320dp。此時手機上的效果會是:可見螢幕的物理尺寸變小。設定後輸入如下結果:

    螢幕寬:640px,螢幕高:1184px,虛擬鍵高:96px
    螢幕寬:320dp,螢幕高:640dp,density:2.0

    也可以再設定回adb shell wm size 720x1280,通過adb shell wm density 360,改成了螢幕寬:320dp。方便測試不同尺寸的螢幕適配問題。此時手機上的效果會是:activity的內容會顯示不全,最右邊部分內容被擠出螢幕外。設定後輸入如下結果:

    螢幕寬:720px,螢幕高:1184px,虛擬鍵高:108px
    螢幕寬:320dp,螢幕高:574dp,density:2.25

    輸入命令adb shell dumpsys window displays或adb shell wm size會得到螢幕解析度,dp值,虛擬鍵高度等。

    螢幕適配方法一,在app下的res下建立values-1184x640等不同解析度的資料夾(本身是1280x640,按上述方法打印出來的螢幕高:1184px),再建dimens.xml檔案,編寫1280x640標準下的dp值。針對圖片則建drawable-hdpi-1184x640等資料夾,放圖片。

    螢幕適配方法二,在app下的res下建立values-sw320dp等資料夾(指1280x640px算下來的螢幕寬是320dp),再建dimens.xml檔案,編寫1280x640標準下的dp值。針對圖片則建drawable-sw320dp-hdpi、drawable-sw320dp-xhdpi等資料夾,放圖片。

    sp與縮放無關的抽象畫素(Scale-independent Pixel)。sp和dp很類似但唯一的區別是,Android系統允許使用者自定義文字尺寸大小(小、正常、大、超大等等),當文字尺寸是“正常”時,1sp=1dp=0.00625英寸,而當文字尺寸是“大”或“超大”時,1sp>1dp=1英寸/160dp=0.00625英寸。類似我們在windows裡調整字型尺寸以後的效果——視窗大小不變,只有文字大小改變。