目前Android最全面、最易懂的Android螢幕適配解決方案
前言
Android的螢幕適配一直以來都在折磨著我們Android開發者,本文將結合:
給你帶來一種全新、全面而邏輯清晰的Android螢幕適配思路,只要你認真閱讀,保證你能解決Android的螢幕適配問題!
目錄
Android螢幕適配解決方案.png
定義
使得某一元素在Android不同尺寸、不同解析度的手機上具備相同的顯示效果
相關重要概念
螢幕尺寸
- 含義:手機對角線的物理尺寸
-
單位:英寸(inch),1英寸=2.54cm
Android手機常見的尺寸有5寸、5.5寸、6寸等等
螢幕解析度
-
含義:手機在橫向、縱向上的畫素點數總和
- 一般描述成螢幕的"寬x高”=AxB
-
含義:螢幕在橫向方向(寬度)上有A個畫素點,在縱向方向
(高)有B個畫素點 - 例子: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,可以保證在不同螢幕畫素密度的裝置上顯示相同的效果
- Android開發時用dp而不是px單位設定圖片大小,是Android特有的單位
- 場景:假如同樣都是畫一條長度是螢幕一半的線,如果使用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
- Android開發時用此單位設定文字大小,可根據字型大小首選項進行縮放
- 推薦使用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