天天看點

Android螢幕适配基本概念

Android螢幕适配基本概念

目錄

一、為什麼要适配

由于Android系統的開放性,任何使用者、開發者、硬體廠商、營運商都可以對Android系統和硬體進行定制,修改成他們想要的樣子。 那麼這種“碎片化”到達什麼程度呢?

Android螢幕适配基本概念

img

以上每一個矩形都代表一種機型,且它們螢幕尺寸、螢幕分辨率大相徑庭。随着Android裝置的增多,裝置碎片化、系統碎片化、螢幕尺寸碎片化、螢幕碎片化的程度也在不斷加深。

備注:

  1. Android系統碎片化:基于Google原生系統,小米定制的MIUI、魅族定制的flyme、華為定制的EMUI等等;
  2. Android機型螢幕尺寸碎片化:5寸、5.5寸、6寸等等;
  3. Android螢幕分辨率碎片化:320x480、480x800、720x1280、1080x1920等;

當Android系統、螢幕尺寸、螢幕密度出現碎片化的時候,就很容易出現同一進制素在不同手機上顯示不同的問題。試想一下這麼一個場景: 為4.3寸螢幕準備的UI設計圖,運作在5.0寸的螢幕上,很可能在右側和下側存在大量的空白;而5.0寸的UI設計圖運作到4.3寸的裝置上,很可能顯示不下。

為了保證使用者獲得一緻的使用者體驗效果,使得某一進制素在Android不同尺寸、不同分辨率的、不同系統的手機上具備相同的顯示效果,能夠保持界面上的效果一緻,我們需要對各種手機螢幕進行适配!

二、基本概念

1、像素(px):

  • 含義:通常所說的像素,就是CCD/CMOS上光電感應元件的數量,一個感光元件經過感光,光電信号轉換,A/D轉換等步驟以後,在輸出的照片上就形成一個點,我們如果把影像放大數倍,會發現這些連續色調其實是由許多色彩相近的小方點所組成,這些小方點就是構成影像的最小機關“像素”(Pixel)。簡而言之,像素就是手機螢幕的最小構成單元。
  • 機關:px(pixel),1px = 1像素點 一般情況下UI設計師的設計圖會以px/dp作為統一的計量機關。

2、分辨率:

  • 含義:手機在橫向、縱向上的像素點數總和 一般描述成 寬*高 ,即橫向像素點個數 * 縱向像素點個數(如1080 x 1920)。
  • 機關:px(pixel),1px = 1像素點

3、螢幕尺寸(inch):

  • 含義:手機對角線的實體尺寸
  • 機關 英寸(inch),一英寸大約2.54cm 常見的尺寸有4.7寸、5寸、5.5寸、6寸

4、螢幕像素密度(dpi):

  • 含義:每英寸長所占的像素點數。 例如每英寸内有160個像素點,則其像素密度為160dpi。
  • 機關:dpi(dots per inch)
  • 計算公式: 像素密度 = 像素 / 尺寸 (dpi = px / in)
  • 标準螢幕像素密度(mdpi): 每英寸長度上還有160個像素點(160dpi),即稱為标準螢幕像素密度(mdpi)。

至于為什麼标準像素密度要設定為160?

簡單說就是為了可以讓像素取整。 下面是具體解釋

實際開發當中,我們經常需要對這幾個尺寸進行互相轉換(比如先在某個分辨率下完成設計,然後縮放到其他尺寸微調後輸出),一般按照 dpi 之間的比例即 2:1.5:1:0.75   來給界面中的元素來進行尺寸定義。

也就是說如果以 160 dpi 作為基準的話,隻要尺寸的 DP 是 4 的公倍數,XHDPI 下乘以 2,HDPI 下乘以 1.5,LDPI 下乘以 0.75 即可滿足所有尺寸下都是整數 pixel 。

但假設以 240 dpi 作為标準,那需要 DP 是 3 的公倍數,XHDPI 下乘以 1.333,MDPI 下乘以 0.666 ,LDPI 下除以 2

而以 LDPI 和 XHDPI 為基準就更複雜了,是以選擇 160 dpi

密度類型 代表的分辨率(PX) 螢幕像素密度(DPI)
低密度(ldpi) 240 x 320 120
中密度(mdpi) 320 x 480 160
高密度(hdpi) 480 x 800 240
超高密度(xhdpi) 720 x 1280 320
超超高密度(xxhdpi) 1080 x 1920 480

螢幕尺寸、分辨率、像素密度三者關系

一部手機的分辨率是寬x高,螢幕大小是以寸為機關,那麼三者的關系是:

Android螢幕适配基本概念

img

假設一部手機的分辨率是1080x1920(px),螢幕大小是5寸

Android螢幕适配基本概念

img

5、密度無關像素(dp):

  • 含義:density-independent pixel,叫dp或dip,與終端上的實際實體像素點無關
  • 機關:dp,可以保證在不同螢幕像素密度的裝置上顯示相同的效果,是安卓特有的長度機關。
  • 場景例子:假如同樣都是畫一條長度是螢幕一半的線,如果使用px作為計量機關,那麼在480x800分辨率手機上設定應為240px;在320x480的手機上應設定為160px,二者設定就不同了;如果使用dp為機關,在這兩種分辨率下,160dp都顯示為螢幕一半的長度。
  • dp與px的轉換:1dp = (dpi / 160 ) * 1px;
密度類型 代表的分辨率(PX) 螢幕密度(DPI) 換算
低密度(ldpi) 240 x 320 120 1dp = 0.75px
中密度(mdpi) 320 x 480 160 1dp=1px
高密度(hdpi) 480 x 800 240 1dp=1.5px
超高密度(xhdpi) 720 x 1280 320 1dp=2px
超超高密度(xxhdpi) 1080 x 1920 480 1dp=3px

6、獨立比例像素(sp):

含義:scale-independent pixel,叫sp或sip

機關:sp,字型大小專用機關 Android開發時用此機關設定文字大小,可根據字型大小首選項進行縮放; 推薦使用12sp、14sp、18sp、22sp作為字型大小,不推薦使用奇數和小數,容易造成精度丢失,12sp以下字型太小。

7、sp 與 dp 的差別:

dp隻跟螢幕的像素密度有關;

sp和dp很類似但唯一的差別是,Android系統允許使用者自定義文字尺寸大小(小、正常、大、超大等等),當文字尺寸是“正常”時1sp=1dp=0.00625英寸,而當文字尺寸是“大”或“超大”時,1sp>1dp=0.00625英寸。類似我們在windows裡調整字型尺寸以後的效果——視窗大小不變,隻有文字大小改變。

追到android源碼,發現系統内部用applyDimension() (路徑:android.util.TypedValue.applyDimension())将所有機關都轉換成px 再處理:

/*
 *
 * @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. 
 */
 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;
 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;
 }
​
 可以發現dp和sp的差別在于density和scaledDensity兩個值上;
​
 /**
 * 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
 */
 public float density;
​
 /**
 * 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.
 */
 public float scaledDensity;
           

8.區分dpi、dp、dip、px、density、分辨率

  • dpi:dots per inch , 直接來說就是一英寸多少個像素點。常見取值 120,160,240。我一般稱作像素密度,簡稱密度
  • density:可以了解為像素密度,手機螢幕dpi與标準mdpi(160dpi)的比值,比如160dpi的手機,density=1,440dpi的手機,density=2.75
  • dp/dip:density-independent pixels 密度無關像素,就是Google工程師們給android定義的一個長度機關,使用這種長度機關,可以使界面元素在不同密度(dpi)的螢幕上保持近似的實體尺寸大小
  • px:pixel 像素,螢幕上顯示元素的最小機關,比如螢幕分辨率1920*1080 px
  • 分辨率:螢幕寬高的像素 比如:1920*1080

9.px、dpi、density各機關的計算

Metrics

在android裡面,擷取一個視窗的metrics,裡面有這麼幾個值

metrics.densityDpi;
metrics.density; 
           

densityDpi : 就是我們常說的dpi,一英寸占多數像素。

density:密度(density=dpi/160) 常見取值1.0 1.5 。

計算dpi

假設一部手機螢幕為4英寸,分辨率為800*480,計算dpi

dpi是指每英寸長所占的像素數量

4英寸是指螢幕對角線長度為4寸

分辨率高800px、寬480px

那麼根據勾股定理可以求得對角線的像素數量

(800平方+480平方)開根号 = 螢幕對角線像素數量

螢幕對角線像素數量 / 4 = dpi

800平方 + 480平方 = 870400

870400開方 = 932.952

932.952 / 4 = 233 (dpi)

也就是說這部手機的dpi是233,接近hdpi

dp與px換算

為什麼要知道這個呢? 因為針對不同的手機dp與px的換算大小是不一樣的,我們有必要知道是什麼決定了他們的大小

換算公式如下:

1 = dpi/160

(dp) (px)

1是指1dp

160是标準密度,也就是mdpi

是以我們能看出來,當dpi為160的時候 1dp=1px,dpi為240(hdpi)時,1dp=1.5px

我們再将這個公式變一下,我們知道density=(dpi/160),是不是和上邊的公式很像,這個公式就可以變為

density*dp = px

可以了解為dp乘上密度就是px

三、适配方案

螢幕适配問題的本質是使得布局、布局元件在Android不同尺寸、不同分辨率的手機上具備相同的顯示效果,下面我将分幾個方面來談談如何去适配。

3.1 關于布局元件的适配:

3.1.1 避免使用像素(px)指定尺寸

由于各種螢幕的像素密度都有所不同,是以相同數量的像素在不同裝置上的實際大小也會有所差異,這樣使用像素(px)定義布局尺寸就會産生問題。 是以,請務必使用密度無關像素 dp 或獨立比例像素 sp 機關指定尺寸。

備注:在生産過程中,廠家不會完全按照螢幕密度标準去生産Android裝置,會在Google的标準周圍浮動變化,或是偏離Google的螢幕密度标準比較大,再加上理論計算(開方)造成的誤差,實際上使用dp作為機關是不能完完全全的完成适配操作。

3.1.2 使用相對布局或線性布局,不要使用絕對布局

對于線性布局(Linearlayout)、相對布局(RelativeLayout)、幀布局(FrameLayout)、絕對布局(AbsoluteLayout)以及新增的加強版幀布局(CoordinatorLayout)需要根據需求進行選擇,沒有絕對而言。 ​ 但因為RelativeLayout講究的是相對位置,即使螢幕的大小改變,視圖之前的相對位置都不會變化,與螢幕大小無關,靈活性很強,而LinearLayout法準确地控制子視圖之間的位置關系,隻能簡單的一個挨着一個地排列,是以,對于螢幕适配來說,使用相對布局(RelativeLayout)将會是更好的解決方案,至于絕對布局由于适配性極差,是以極少使用。

3.1.3 使用wrap_content、match_parent、權重

使用 “wrap_content” 和 “match_parent” 尺寸值而不是寫死的尺寸,系統會自動計算相應的數值,視圖就會相應地使用自身所需的空間或填滿可用空間,讓布局正确适應各種螢幕尺寸和螢幕方向,元件的權重比同理。

3.1.4 使用minWidth、minHeight、lines等屬性

很多時候我們顯示的資料都是由背景傳回的,再由我們加工處理後去适配我們的元件,這些資料的長度我們是無法确定的,而正常情況下我們構思的布局都僅是适用于理想的情況下,為了保證界面的對齊、資料顯示完整等等的原因,我們需要在構思布局時增加對元件最小寬高度、行數等屬性的設定,確定在特殊的資料下不會破壞我們的整體布局。

3.1.5 使用dimens

元件的長寬我們可以通過dimens來定義,不同的螢幕尺寸可以定義不同的數值,或者是不同的語言顯示我們也可以定義不同的數值,因為翻譯後的長度一般都不會跟中文的一緻。

3.2 成熟的适配架構

3.2.1 生成多套Dimens适配

最常用效果最好的适配方案

3.2.2 針對density轉換px适配(今日頭條的适配方案)

最便捷的适配方案

AndroidAutoSize

https://github.com/JessYanCoding/AndroidAutoSize

https://www.jianshu.com/p/4aa23d69d481