1. 程式人生 > >目前Android最全面、最易懂的Android螢幕適配解決方案

目前Android最全面、最易懂的Android螢幕適配解決方案

前言

Android的螢幕適配一直以來都在折磨著我們Android開發者,本文將結合:

給你帶來一種全新、全面而邏輯清晰的Android螢幕適配思路,只要你認真閱讀,保證你能解決Android的螢幕適配問題!

目錄


Android螢幕適配解決方案.png

定義

使得某一元素在Android不同尺寸、不同解析度的手機上具備相同的顯示效果

相關重要概念

螢幕尺寸

  • 含義:手機對角線的物理尺寸
  • 單位:英寸(inch),1英寸=2.54cm

    Android手機常見的尺寸有5寸、5.5寸、6寸等等

螢幕解析度

  • 含義:手機在橫向、縱向上的畫素點數總和
    1. 一般描述成螢幕的"寬x高”=AxB
    2. 含義:螢幕在橫向方向(寬度)上有A個畫素點,在縱向方向
      (高)有B個畫素點
    3. 例子:1080x1920,即寬度方向上有1080個畫素點,在高度方向上有1920個畫素點
  • 單位:px(pixel),1px=1畫素點

    UI設計師的設計圖會以px作為統一的計量單位

  • Android手機常見的解析度:320x480、480x800、720x1280、1080x1920

螢幕畫素密度

  • 含義:每英寸的畫素點數
  • 單位:dpi(dots per ich)

    假設裝置內每英寸有160個畫素,那麼該裝置的螢幕畫素密度=160dpi

  • 安卓手機對於每類手機螢幕大小都有一個相應的螢幕畫素密度:
密度型別 代表的解析度(px) 螢幕畫素密度(dpi)
低密度(ldpi) 240x320 120
中密度(mdpi) 320x480 160
高密度(hdpi) 480x800 240
超高密度(xhdpi) 720x1280 320
超超高密度(xxhdpi) 1080x1920 480

螢幕尺寸、解析度、畫素密度三者關係

一部手機的解析度是寬x高,螢幕大小是以寸為單位,那麼三者的關係是:


三者關係示意圖


數學不太差的人應該能懂.....吧?

不懂沒關係,在這裡舉個例子
假設一部手機的解析度是1080x1920(px),螢幕大小是5寸,問密度是多少?
解:請直接套公式


解答過程

密度無關畫素

  • 含義:density-independent pixel,叫dp或dip,與終端上的實際物理畫素點無關。
  • 單位:dp,可以保證在不同螢幕畫素密度的裝置上顯示相同的效果

    1. Android開發時用dp而不是px單位設定圖片大小,是Android特有的單位
    2. 場景:假如同樣都是畫一條長度是螢幕一半的線,如果使用px作為計量單位,那麼在480x800解析度手機上設定應為240px;在320x480的手機上應設定為160px,二者設定就不同了;如果使用dp為單位,在這兩種解析度下,160dp都顯示為螢幕一半的長度。
  • dp與px的轉換
    因為ui設計師給你的設計圖是以px為單位的,Android開發則是使用dp作為單位的,那麼我們需要進行轉換:

密度型別 代表的解析度(px) 螢幕密度(dpi) 換算(px/dp) 比例
低密度(ldpi) 240x320 120 1dp=0.75px 3
中密度(mdpi) 320x480 160 1dp=1px 4
高密度(hdpi) 480x800 240 1dp=1.5px 6
超高密度(xhdpi) 720x1280 320 1dp=2px 8
超超高密度(xxhdpi) 1080x1920 480 1dp=3px 12

在Android中,規定以160dpi(即螢幕解析度為320x480)為基準:1dp=1px

獨立比例畫素

  • 含義:scale-independent pixel,叫sp或sip
  • 單位:sp
    1. Android開發時用此單位設定文字大小,可根據字型大小首選項進行縮放
    2. 推薦使用12sp、14sp、18sp、22sp作為字型設定的大小,不推薦使用奇數和小數,容易造成精度的丟失問題;小於12sp的字型會太小導致使用者看不清

請把上面的概念記住,因為下面講解都會用到!

為什麼要進行Android螢幕適配

由於Android系統的開放性,任何使用者、開發者、OEM廠商、運營商都可以對Android進行定製,於是導致:

  • Android系統碎片化:小米定製的MIUI、魅族定製的flyme、華為定製的EMUI等等

    當然都是基於Google原生系統定製的

  • Android機型螢幕尺寸碎片化:5寸、5.5寸、6寸等等
  • Android螢幕解析度碎片化:320x480、480x800、720x1280、1080x1920

    據友盟指數顯示,統計至2015年12月,支援Android的裝置共有27796種

當Android系統、螢幕尺寸、螢幕密度出現碎片化的時候,就很容易出現同一元素在不同手機上顯示不同的問題。

試想一下這麼一個場景:
為4.3寸螢幕準備的UI設計圖,執行在5.0寸的螢幕上,很可能在右側和下側存在大量的空白;而5.0寸的UI設計圖執行到4.3寸的裝置上,很可能顯示不下。

為了保證使用者獲得一致的使用者體驗效果:

使得某一元素在Android不同尺寸、不同解析度的手機上具備相同的顯示效果

於是,我們便需要對Android螢幕進行適配。

螢幕適配問題的本質

  • 使得“佈局”、“佈局元件”、“圖片資源”、“使用者介面流程”匹配不同的螢幕尺寸

    使得佈局、佈局元件自適應螢幕尺寸;
    根據螢幕的配置來載入相應的UI佈局、使用者介面流程

  • 使得“圖片資源”匹配不同的螢幕密度

解決方案

  • 問題:如何進行螢幕尺寸匹配?
  • 答:

螢幕尺寸適配解決方案.png

“佈局”匹配

本質1:使得佈局元素自適應螢幕尺寸

  • 做法
    使用相對佈局(RelativeLayout),禁用絕對佈局(AbsoluteLayout)

開發中,我們使用的佈局一般有:

  • 線性佈局(Linearlayout)
  • 相對佈局(RelativeLayout)
  • 幀佈局(FrameLayout)
  • 絕對佈局(AbsoluteLayout)

由於絕對佈局(AbsoluteLayout)適配性極差,所以極少使用。

對於線性佈局(Linearlayout)、相對佈局(RelativeLayout)和幀佈局(FrameLayout)需要根據需求進行選擇,但要記住:

  • RelativeLayout
    佈局的子控制元件之間使用相對位置的方式排列,因為RelativeLayout講究的是相對位置,即使螢幕的大小改變,檢視之前的相對位置都不會變化,與螢幕大小無關,靈活性很強
  • LinearLayout
    通過多層巢狀LinearLayout和組合使
    用"wrap_content"和"match_parent"已經可以構建出足夠複雜的佈局。但是LinearLayout無法準確地控制子檢視之間的位置關係,只能簡單的一個挨著一個地排列

所以,對於螢幕適配來說,使用相對佈局(RelativeLayout)將會是更好的解決方案

本質2:根據螢幕的配置來載入相應的UI佈局

應用場景:需要為不同螢幕尺寸的裝置設計不同的佈局

  • 做法:使用限定符
  • 作用:通過配置限定符使得程式在執行時根據當前裝置的配置(螢幕尺寸)自動載入合適的佈局資源
  • 限定符型別:
    • 尺寸(size)限定符
    • 最小寬度(Smallest-width)限定符
    • 佈局別名
    • 螢幕方向(Orientation)限定符

尺寸(size)限定符

  • 使用場景:當一款應用顯示的內容較多,希望進行以下設定:
    • 在平板電腦和電視的螢幕(>7英寸)上:實施“雙面板”模式以同時顯示更多內容
    • 在手機較小的螢幕上:使用單面板分別顯示內容

因此,我們可以使用尺寸限定符(layout-large)通過建立一個檔案

res/layout-large/main.xml

來完成上述設定:

  • 讓系統在螢幕尺寸>7英寸時採用適配平板的雙面板佈局
  • 反之(預設情況下)採用適配手機的單面板佈局

檔案配置如下:

  • 適配手機的單面板(預設)佈局:res/layout/main.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="vertical"
      android:layout_width="match_parent"
      android:layout_height="match_parent">
    
      <fragment android:id="@+id/headlines"
                android:layout_height="fill_parent"
                android:name="com.example.android.newsreader.HeadlinesFragment"
                android:layout_width="match_parent" />
    </LinearLayout>
  • 適配尺寸>7寸平板的雙面板佈局::res/layout-large/main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal">
    <fragment android:id="@+id/headlines"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.HeadlinesFragment"
              android:layout_width="400dp"
              android:layout_marginRight="10dp"/>
    <fragment android:id="@+id/article"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.ArticleFragment"
              android:layout_width="fill_parent" />
</LinearLayout>

請注意:

  • 兩個佈局名稱均為main.xml,只有佈局的目錄名不同:第一個佈局的目錄名為:layout,第二個佈局的目錄名為:layout-large,包含了尺寸限定符(large)
  • 被定義為大屏的裝置(7寸以上的平板)會自動載入包含了large限定符目錄的佈局,而小屏裝置會載入另一個預設的佈局

但要注意的是,這種方式只適合Android 3.2版本之前。

最小寬度(Smallest-width)限定符

  • 背景:上述提到的限定符“large”具體是指多大呢?似乎沒有一個定量的指標,這便意味著可能沒辦法準確地根據當前裝置的配置(螢幕尺寸)自動載入合適的佈局資源
  • 例子:比如說large同時包含著5寸和7寸,這意味著使用“large”限定符的話我沒辦法實現為5寸和7寸的平板電腦分別載入不同的佈局

於是,在Android 3.2及之後版本,引入了最小寬度(Smallest-width)限定符

定義:通過指定某個最小寬度(以 dp 為單位)來精確定位螢幕從而載入不同的UI資源

  • 使用場景

    你需要為標準 7 英寸平板電腦匹配雙面板佈局(其最小寬度為 600 dp),在手機(較小的螢幕上)匹配單面板佈局

解決方案:您可以使用上文中所述的單面板和雙面板這兩種佈局,但您應使用 sw600dp 指明雙面板佈局僅適用於最小寬度為 600 dp 的螢幕,而不是使用 large 尺寸限定符。

  • sw xxxdp,即small width的縮寫,其不區分方向,即無論是寬度還是高度,只要大於 xxxdp,就採用次此佈局
  • 例子:使用了layout-sw 600dp的最小寬度限定符,即無論是寬度還是高度,只要大於600dp,就採用layout-sw 600dp目錄下的佈局

程式碼展示:

  • 適配手機的單面板(預設)佈局:res/layout/main.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="vertical"
      android:layout_width="match_parent"
      android:layout_height="match_parent">
    
      <fragment android:id="@+id/headlines"
                android:layout_height="fill_parent"
                android:name="com.example.android.newsreader.HeadlinesFragment"
                android:layout_width="match_parent" />
    </LinearLayout>
  • 適配尺寸>7寸平板的雙面板佈局:res/layout-sw600dp/main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal">
    <fragment android:id="@+id/headlines"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.HeadlinesFragment"
              android:layout_width="400dp"
              android:layout_marginRight="10dp"/>
    <fragment android:id="@+id/article"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.ArticleFragment"
              android:layout_width="fill_parent" />
</LinearLayout>
  • 對於最小寬度≥ 600 dp 的裝置
    系統會自動載入 layout-sw600dp/main.xml(雙面板)佈局,否則系統就會選擇 layout/main.xml(單面板)佈局
    (這個選擇過程是Android系統自動選擇的)

使用佈局別名

設想這麼一個場景

當你需要同時為Android 3.2版本前和Android 3.2版本後的手機進行螢幕尺寸適配的時候,由於尺寸限定符僅用於Android 3.2版本前,最小寬度限定符僅用於Android 3.2版本後,所以這會帶來一個問題,為了很好地進行螢幕尺寸的適配,你需要同時維護layout-sw600dp和layout-large的兩套main.xml平板佈局,如下:

  • 適配手機的單面板(預設)佈局:res/layout/main.xml