1. 程式人生 > >Android 螢幕各種引數的介紹和學習

Android 螢幕各種引數的介紹和學習

文章目錄


經常被 Android 裝置紛繁的螢幕搞得是暈頭轉向,下面就梳理一下 Android 中的相關概念。

一、概念

1.1 螢幕大小

螢幕大小是手機對角線的物理尺寸,單位是:英寸(inch),1 inch =2.54 cm(釐米) 。例如現在手機大多都是 “6.0寸” 以上的螢幕,這個就是對角線的尺寸,6.0(inch) X 2.54(cm)/ 1 (inch)= 15.24(cm)

1.2 螢幕解析度

解析度就是手機螢幕的畫素點數,一般描述為:縱畫素 * 橫畫素,如 2240 * 1080,就是在縱方向上有2240個畫素點,在橫方向上有1080個畫素點。

1.3 螢幕畫素密度

螢幕畫素密度(dpi,dots per inch;或 PPI ,pixels per inch),就是每英寸的畫素點,數值越高顯示越細膩。假如一部手機的解析度是 1080*1920 ,螢幕大小是5英寸,那麼此螢幕的密度是多少呢?通過寬1080和高1920,根據勾股定理,得出對角線的畫素大約是2203,那麼用2203/5=440,440dpi就是螢幕的畫素螢幕密度。
在這裡插入圖片描述

1.4 實際密度和系統密度

這裡其實將的還是上面的 螢幕畫素密度

,不過是換了一種說法。

實際密度:就是我們自己算出來的密度,這個密度代表了螢幕真實的細膩程度,如上述例子中的440dpi 就是實際密度,說明這塊螢幕每寸有440個畫素。5英寸1080*1920 的螢幕密度是440,而相同解析度的4.5英寸螢幕是490。如此看來,螢幕密度會出現很多數值,呈現嚴重的碎片化。而密度有時 Android 螢幕將介面進行顯示的依據,那麼 Android 是如何適配這麼多螢幕的呢?其實,每部手機螢幕都有一個初始固定密度,這些數值是120、160、240、320、480,我們權且稱為“系統密度”。大家發現規律沒有?相隔數值之間是2倍的關係。一般情況下,240*320的螢幕是低密度120dpi,即 ldpi

;320*480的螢幕是中密度160dpi,即 mdpi ;480*800的螢幕是高密度240dpi,即 hdpi ;720*1280的螢幕是超高密度320dpi,即xhdpi ;1080*1920的螢幕密度是超超高密度480dpi,即 xxhdpi

  在具體的 Android 專案下,這些表示不同螢幕密度(不同解析度)用來修飾 Androiddrawable 資料夾以及 value 資料夾,用來區分不同畫素密度下的圖片和 dimen 值,所以在不同 drawable 資料夾下圖片的 densityDpi 的值也是不同的 。這會導致用 BitmapFactorydecodeResource建立 Bitmap 時,其載入到記憶體的大小不一樣。(詳見 深入理解Android Bitmap的各種操作
Google官方指定按照下列標準進行區分:

名稱 畫素密度範圍
mdpi 120dpi ~ 160dpi
hdpi 160dpi ~ 240dpi
xhdpi 240dpi ~ 320dpi
xxhdpi 320dpi ~ 480dpi
xxxhdpi 480dpi ~ 640dpi

1.5 dp

dp 也可以寫成dipdensity independent pixel),即密度無關的畫素。比如,一張寬和高均為100dp的圖片在 320 *480 和480*800的手機上,“看起來”是一樣大,實際上,它們的畫素值並不一樣。dp正是這樣一個尺寸,不管這個螢幕的密度是多少,螢幕上相同dp的大小的元素看起來始終差不多大。另外,文字尺寸使用 sp,即 scale independent pixel 的縮寫,與 dp 類似,是設定字型大小的御用單位。在 Android 中,系統密度為160dpi的中密度手機螢幕為基準螢幕,即320*480的手機螢幕。在這個螢幕中:1dp = 1px

100dp在320*480(mdpi,160dpi)中是100px。那麼100dp在480*800(hdpi,240dpi)的手機上,根據160與240的比例關係,100dp實際覆蓋了150px。因此,如果你為mdpi手機上提供了一張100px的圖片,這張圖片在hdpi手機上就會拉伸至150px,但是他們都是100dp。要注意一點的就是:dp和px的換算要以系統密度為準,720*1280的系統密度為320,320*480的系統密度為160,320/160=2,那麼在720*1280中,1dp = 2px。同理,在1080*1920中,1dp = 3px。有一個dp和px換算的比例公式:ldpi : mdpi :hdpi:xdpi:xxdpi = 3:4:6:8:12,我們發現相隔數字之間還是2倍的關係。計算的時候,以 mdpi 為基準。如果以 mdpi 為基準比例為:
dpi : mdpi :hdpi:xdpi:xxdpi = 0.75:1:1.5:2:3
在這裡插入圖片描述

二、從系統中獲取相關引數和轉換

2.1 DisplayMetrics

這個類是 Android 提供的記述螢幕有關資訊的一種類,諸如其尺寸、螢幕畫素密度等。
獲取這個物件的方法:

//第一種
DisplayMetrics metrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);

//第二種
DisplayMetrics metrics=activity.getResources().getDisplayMetrics();

//第三種
Resources.getSystem().getDisplayMetrics();

這個類中有幾個比較重要的屬性:

	/**
     * The absolute width of the available display size in pixels.
     * 裝置的絕對寬度,單位是px
     */
    public int widthPixels;
    
    /**
     * The absolute height of the available display size in pixels.
     * 裝置的絕對高度,單位是px
     */
    public int heightPixels;
    
     /**
     * The logical density of the display.  This is a scaling factor for the
     * Density Independent Pixel unit, where one DIP is one pixel on an
     * approximately 160 dpi screen (for example a 240x320, 1.5"x2" screen), 
     * providing the baseline of the system's display. Thus on a 160dpi screen 
     * this density value will be 1; on a 120 dpi screen it would be .75; etc.
     *  
     * <p>This value does not exactly follow the real screen size (as given by 
     * {@link #xdpi} and {@link #ydpi}, but rather is used to scale the size of
     * the overall UI in steps based on gross changes in the display dpi.  For 
     * example, a 240x320 screen will have a density of 1 even if its width is 
     * 1.8", 1.3", etc. However, if the screen resolution is increased to 
     * 320x480 but the screen size remained 1.5"x2" then the density would be 
     * increased (probably to 1.5).
     *
     * @see #DENSITY_DEFAULT
     *簡單來說,可以理解為 density 的數值是 1dp = density px 即 density = dpi/160,也就是在我們介紹從低到高系統密度的比值:
     *  0.75 : 1 : 1.5 : 2 : 3
     */
    public float density;
    
    /**
     * The screen density expressed as dots-per-inch.  May be either
     * {@link #DENSITY_LOW}, {@link #DENSITY_MEDIUM}, or {@link #DENSITY_HIGH}.
     *  就是上面的:螢幕畫素密度(dpi)
     */
    public int densityDpi;
    
    /**
     * A scaling factor for fonts displayed on the display.  This is the same
     * as {@link #density}, except that it may be adjusted in smaller
     * increments at runtime based on a user preference for the font size.
     * 字型顯示的縮放因子,跟上面的 density 是一樣的
     */
    public float scaledDensity;
    
    /**
     * The exact physical pixels per inch of the screen in the X dimension.
     * 水平方向上的dpi
     */
    public float xdpi;
    
    /**
     * The exact physical pixels per inch of the screen in the Y dimension.
     * 豎直方向上的dpi
     */
    public float ydpi;

DisplayMetrics 中,densitydensityDpi 這個兩個的線性關係:

density 1 1.5 2 3 3.5 4
densityDpi 160 240 320 480 560 640

2.2 TypedValue

TypedValueAndroid 提供單位轉換的類,這個類是工具類,作為一個動態容器,它存放一些資料值,這些值主要是 resource 中的值。TypedValue 類把對應的值轉化為實際螢幕上的點值,也就是畫素值,總體來說作用:把 Android 系統中的非標準度量尺寸轉變為標準度量尺寸(Android 系統中的標準尺寸是 px,即畫素)。非標準單位:dp 、in、mm、pt、sp
站在巨人的肩膀上:典型應用為:

 /**
     * Converts an unpacked complex data value holding a dimension to its final floating 
     * point value. The two parameters <var>unit</var> and <var>value</var>
     * are as in {@link #TYPE_DIMENSION}.
     *  
     * @param unit The unit to convert from.
     * @param value The value to apply the unit to.
     * @param metrics Current display metrics to use in the conversion -- 
     *                supplies display density and scaling information.
     * 
     * @return The complex floating point value multiplied by the appropriate 
     * metrics depending on its unit. 
     */
TypedValue.applyDimension(int unit, float value, DisplayMetrics metrics)

其中,第一個引數 unit 是你需要轉換的單位,第二個引數 value 是你需要得到的單位數值,第三個引數 metrics 封裝了螢幕區域各種屬性。
例如:我要得到一個 20dp 在當前裝置上對應的 px 值:


float px_value = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,20,context.getResources().getDisplayMetrics());

還有其他型別:

TypedValue.applyDimension()方法的功能就是把非標準尺寸轉換成標準尺寸:

dp->px:  TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, context.getResources().getDisplayMetrics());

in->px: TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_IN, 20, context.getResources().getDisplayMetrics());

mm->px: TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 20, context.getResources().getDisplayMetrics());

pt->px: TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PT, 20, context.getResources().getDisplayMetrics());

sp->px: TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, context.getResources().getDisplayMetrics());

不積跬步無以至千里,不積小流無以成江海。讓我們默默前行,不蹉跎歲月,不辜負自己。突然想到家園的歌詞:冰雪早已覆蓋我的足跡,遠方的炊煙搖曳溫暖的召喚,風兒無法吹斷我回望的視線,家園好像永遠征途漫漫。是啊,我們人生也是征途漫漫。

站在巨人的肩膀上:
UI設計師不可不知的安卓螢幕知識
Android螢幕適配及DisplayMetrics解析