(轉)Android適配全面總結(一)----屏幕適配

原文地址:http://www.lxweimin.com/p/9755da0f4e8f

前言

Android適配是一個老生常談的問題,很多程序員覺得很惡心,不愿意做適配,但是又不得不做。然后老板說,這位兄弟,做好了,今天晚飯給你加個雞腿,然后程序員開始找各種資料,忙活起來了,最終在苦逼的煎熬中做完了。

好了,言歸正傳,根據(jù)多年開發(fā)經驗,總結一下Android適配主要表現(xiàn)在以下 3個方面:

1、屏幕適配。(網(wǎng)上講的最多的就是這個。) 由于Android碎片化嚴重,導致開發(fā)中一套代碼在不同手機上運行起來效果不是很好,兼容性不是很好,這就需要對不同分辨率,不同屏幕大小的手機做屏幕適配。

2、版本適配。 不同的系統(tǒng)版本api有所變更,既要適配高版本,也要做到兼容低版本。

具體講解請看鏈接: http://www.lxweimin.com/p/49fa8ebc0105

3、ROM適配。(這個是最難的,工作量也是最大的,如果沒有不同版本手機適配的積累,遇到問題都不知道怎么解決。) 由于Android是開源的,不同的手機廠商有自己定制的ROM,對系統(tǒng)的api可能有變更,也有可能新增一些api,所以在開發(fā)中,要針對不同廠商的手機做一些特殊適配。

具體講解請看鏈接: http://www.lxweimin.com/p/f9c67a4b908e

[圖片上傳失敗...(image-56b23a-1517901336150)]

廢話少說,開始進入正題。這篇文章我們先講解第一個問題 ---- 屏幕適配。

一、屏幕適配是啥(可能有人不懂,我在此簡單解釋一下)?

程序猿把設計獅制作的效果圖應用到不同的手機,對不同的屏幕進行界面調整的過程,確保界面不變形,呈現(xiàn)效果圖的位置、尺寸、比例。

二、需要掌握的幾個知識點。

(1)屏幕物理尺寸

屏幕對角線的尺寸。單位是英寸,1英寸 ≈ 2.54厘米

比如常見的屏幕尺寸有5.0、5.1、5.2、5.5、5.7、5.9、6.0等

(2)屏幕分辨率

  • 定義:

    確定計算機屏幕上顯示多少信息的設置,以水平和垂直像素來衡量。

  • 計算公式:

    屏幕分辨率 = 橫向像素*縱向像素(或者 寬x高),如 1080*1920

  • 單位:

    單位是px,1px=1個像素點。

  • 常見分辨率:

720x1280、1080x1920(當然還有480x800,這個很少見了)

(3)屏幕像素密度(dots per inch)

  • 含義:每英寸上的像素點數(shù)。

    屏幕像素密度與屏幕尺寸和屏幕分辨率有關,在單一變化條件下,屏幕尺寸越小、分辨率越高,像素密度越大,反之越小。

  • 單位:dpi(dots per inch)

    假設設備內每英寸有240個像素,那么該設備的屏幕像素密度=240dpi

  • 不同手機屏幕大小對應的屏幕像素密度關系表:

密度類型 代表的分辨率(px) 屏幕像素密度(dpi)
低密度(ldpi) 240x320 120
中密度(mdpi) 320x480 160
高密度(hdpi) 480x800 240
超高密度(xhdpi) 720x1280 320
超超高密度(xxhdpi) 1080x1920 480
  • 當然與像素有關的還有一個單位ppi,這個我們安卓中用不到,有興趣的可以百度一下。

(4)以上三者(屏幕尺寸、分辨率、像素密度)之間的關系

[圖片上傳失敗...(image-760079-1517901336150)]

(5)密度無關像素(dp 或 dip)

  • 單位:dp,可以保證在不同屏幕像素密度的設備上顯示相同的效果

  • Android開發(fā)設置布局和控件寬高,用dp而不是px,dp是Android特有的單位

  • dp與px的轉換

    因為ui給的圖是以 px 為單位的,Android開發(fā)則是使用 dp 作為單位的,那么我們需要進行轉換:

    在Android中,規(guī)定以160dpi(即屏幕分辨率為320x480)為基準:1dp=1px

[圖片上傳失敗...(image-5703d9-1517901336150)]

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

  • 單位:sp
  • Android開發(fā)時用sp設置文字大小,使用它可以根據(jù)文字大小首選項進行放縮。
  • 不推薦使用奇數(shù)和小數(shù),容易造成精度的丟失問題;小于12sp的字體會太小導致用戶看不清。

下面給一個實例說明,讓你更能明白這幾個單位:

看下圖你可以知道:為什么使用了dp作為單位,兩個手機分辨率也是一樣的,可是按鈕顯示的寬度還是不一樣?

[圖片上傳失敗...(image-dcf11e-1517901336150)]


三、屏幕適配的本質

總結一下,主要有以下兩點:

  • (1)使得“布局”、“布局組件”、“圖片資源”、“用戶界面流程”匹配不同的屏幕尺寸

  • (2)使得“圖片資源”匹配不同的屏幕密度

四、屏幕適配具體的解決方案

首先看一張圖:

[圖片上傳失敗...(image-56f1bf-1517901336150)]

4.1 屏幕尺寸適配

4.1.1.布局適配

  • 4.1.1.1. 使得布局元素自適應屏幕尺寸

解決方案:使用相對布局(RelativeLayout),禁用絕對布局(AbsoluteLayout)。這個很基礎,就不多說了。

  • 4.1.1.2. 根據(jù)屏幕的配置來加載相應的UI布局。為不同屏幕尺寸的設備設計不同的布局。

解決方案:使用限定符。通過配置限定符使得程序在運行時根據(jù)當前設備的配置(屏幕尺寸)自動加載合適的布局資源。

限定符分類:
(1)尺寸(size)限定符(這種方式只適合Android 3.2版本之前
??res目錄新建一個layout-large文件夾,布局名字和res/layout里面的同名。在平板電腦和電視的屏幕(>7英寸)上:實施 雙面板 模式以同時顯示更多內容,它會加載res/layout-large里面的布局,在手機較小的屏幕上:使用 單面板 分別顯示內容,加載的是res/layout里面的同名布局。

[圖片上傳失敗...(image-ea8a8d-1517901336150)]

(2)最小寬度(Smallest-width)限定符。
??通過指定某個最小寬度(以 dp 為單位)來精確定位屏幕從而加載不同的UI資源。(適用于Android 3.2及之后版本
??最小寬度限定符可讓您通過指定某個最小寬度(以 dp 為單位)來定位屏幕。例如,標準 7 英寸平板電腦的最小寬度為 600 dp,因此如果您要在此類屏幕上的用戶界面中使用雙面板(但在較小的屏幕上只顯示列表),您可以使用上文中所述的單面板和雙面板這兩種布局,但您應使用 sw600dp 指明雙面板布局僅適用于最小寬度為 600 dp 的屏幕,而不是使用 large 尺寸限定符。

[圖片上傳失敗...(image-99902e-1517901336150)]

(3)布局別名
??為了解決文件名的重復從而帶來一些列后期維護的問題,我們使用 布局別名 方案。
通過以上兩點,大家也會發(fā)現(xiàn)一個問題:
??適配手機沒問題。但是適配平板發(fā)現(xiàn)Android3.2前后的這兩個文件內容是一樣的,只是文件名不同而已。

適配手機的單面板(默認)布局:res/layout/main.xml
適配尺寸>7寸平板的雙面板布局(Android 3.2前):res/layout-large/main.xml
適配尺寸>7寸平板的雙面板布局(Android 3.2后)res/layout-sw600dp/main.xml

解救方案:取一個別名就好了,示例如下:

[圖片上傳失敗...(image-4de77a-1517901336150)]

這樣兩個layout.xml都只是引用了@layout/main_twopanes,就避免了重復定義布局文件的情況

(4)屏幕方向(Orientation)限定符。
??根據(jù)屏幕方向進行布局的調整。
??某些布局會同時支持橫向模式和縱向模式,但我們可以通過調整優(yōu)化其中大部分布局的效果。每種屏幕尺寸和屏幕方向下的布局行為方式如下所示:

  • 小屏幕,縱向:單面板,帶徽標
  • 小屏幕,橫向:單面板,帶徽標
  • 7 英寸平板電腦,縱向:單面板,帶操作欄
  • 7 英寸平板電腦,橫向:雙面板,寬,帶操作欄
  • 10 英寸平板電腦,縱向:雙面板,窄,帶操作欄
  • 10 英寸平板電腦,橫向:雙面板,寬,帶操作欄
  • 電視,橫向:雙面板,寬,帶操作欄

解決方案:
第一步:先定義類別:單/雙面板、是否帶操作欄、寬/窄

定義在 res/layout/ 目錄下的某個 XML 文件中

第二步:再進行相應的匹配:屏幕尺寸(小屏、7寸、10寸)、方向(橫、縱)

使用布局別名進行匹配

示例代碼如下圖所示:

[圖片上傳失敗...(image-76a7a1-1517901336150)]

這里沒有完全把全部尺寸匹配類型的代碼貼出來,大家可以自己去嘗試把其補充完整。


4.1.2. 布局組件適配
使得布局組件自適應屏幕尺寸。

  • 解決方案:使用"wrap_content"、"match_parent"和"weight“來控制視圖組件的寬度和高度。這個很基礎,這幾個的用法大家應該都經常用的,就不多說了。

4.1.3. 圖片資源適配
使得圖片資源在不同屏幕密度上顯示相同的像素效果。

在實際開發(fā)中一個按鈕的背景圖片必須能夠隨著按鈕大小的改變而改變。使用普通的圖片將無法實現(xiàn)這個效果,因為運行時會對圖片均勻地拉伸或壓縮。

  • 解決方案:使用自動拉伸位圖(nine-patch圖片),后綴名是.9.png,它是一種被特殊處理過的PNG圖片,設計時可以指定圖片的拉伸區(qū)域和非拉伸區(qū)域;使用時,系統(tǒng)就會根據(jù)控件的大小自動地拉伸你想要拉伸的部分。

  • 注意事項:

    • 1.必須使用UI給的圖片格式(.9.png后綴),隨意更改后綴使用在項目中會報錯,因為系統(tǒng)就是根據(jù)這個來區(qū)別nine-patch圖片和普通的PNG圖片的。
    • 2.部分nine-patch圖片在Android Studio項目中不能識別,會報錯,需要謹慎使用。
  • 下面一張圖看看使用nine-patch圖片的效果:

[圖片上傳失敗...(image-c85be1-1517901336150)]

nine-patch圖片制作請參考我的博客:
nine-patch圖片的制作


4.1.4. 用戶界面流程適配
根據(jù)屏幕的配置來加載相應的用戶界面流程。

  • 使用場景:我們會根據(jù)設備特點顯示恰當?shù)牟季郑沁@樣做,會使得用戶界面流程可能會有所不同。
    ??例如:如果應用處于雙面板模式下,點擊左側面板上的項即可直接在右側面板上顯示相關內容;而如果該應用處于單面板模式下,點擊相關的內容應該跳轉到另外一個Activity進行后續(xù)的處理。

  • 解決方案(最終目的是進行用戶界面流程的自適應配置,其實就是用java代碼動態(tài)加載):

① 確定當前布局。示例如下:

由于每種布局的實施都會稍有不同,因此我們需要先確定當前向用戶顯示的布局。
例如,我們可以先了解用戶所處的是“單面板”模式還是“雙面板”模式。

[圖片上傳失敗...(image-445610-1517901336150)]

② 根據(jù)當前布局做出響應。示例如下:

有些操作可能會因當前的具體布局而產生不同的結果。
例如,在新聞閱讀器示例中,如果用戶界面處于雙面板模式下,那么點擊標題列表中的標題就會在右側面板中切換到相應報道(Fragment);但如果用戶界面處于單面板模式下,那么上述操作就會啟動一個獨立Activity:

[圖片上傳失敗...(image-3f46db-1517901336150)]

③ 重復使用其他 Activity 中的 Fragment。示例如下:

例如,在新聞閱讀器示例中,對于較大的屏幕,新聞報道文本會顯示在右側 Fragment 面板中;但對于較小的屏幕,這些文本就會以獨立 Activity 的形式存在。

[圖片上傳失敗...(image-401931-1517901336150)]

④ 處理屏幕配置變化。示例如下:

如果我們使用獨立Activity實施界面的獨立部分,那么請注意,我們可能需要對特定配置變化(例如屏幕方向的變化)做出響應,以便保持界面的一致性。

例如,在運行 Android 3.0 或更高版本的標準 7 英寸平板電腦上,如果新聞閱讀器示例應用運行在縱向模式下,就會在使用獨立Activity 顯示新聞報道;但如果該應用運行在橫向模式下,就會使用雙面板布局。

[圖片上傳失敗...(image-2daf08-1517901336150)]

4.2 屏幕密度適配

4.2.1.布局控件適配
使得布局組件在不同屏幕密度上顯示相同的像素效果。

解決方案有以下兩種:

  • (1)使用 密度無關像素 ( dp ) 或 獨立比例像素( sp ) 作為計量單位。

    • 使用場景:假如同樣都是畫一條長度是屏幕一半的線,如果使用px作為計量單位,那么在480x800分辨率手機上設置應為240px;在320x480的手機上應設置為160px,二者設置就不同了;如果使用dp為單位,在這兩種分辨率下,160dp都顯示為屏幕一半的長度。
    • dppx 的轉換在前面有介紹,這里就不說了。
    • 為了能夠進行不同屏幕像素密度的匹配,應該這樣做:
    1\. 使用dp來代替px作為控件寬高的統(tǒng)一度量單位。
    2\. 使用sp作為文字的統(tǒng)一度量單位。
    
    

有下面一種場景:
RelativeLayout布局里面,水平方向上放置兩個按鈕,一個是150dp左對齊,另外一個是200dp右對齊。在屏幕總寬度為360dp的Nexus5上中間有10dp的間隙。但同樣地設置在Nexus S(屏幕寬度是320dp),會發(fā)現(xiàn),兩個按鈕會重疊,因為320dp<200+150dp。
如圖:

[圖片上傳失敗...(image-148011-1517901336150)]

[圖片上傳失敗...(image-a4d44a-1517901336150)]

從上面可以看出,由于Android屏幕設備的多樣性,如果使用dp來作為度量單位,并不是所有的屏幕的寬度都具備相同的dp長度。
dp解決了同一數(shù)值在 不同分辨率 中展示 相同尺寸大小 的問題(即屏幕像素密度匹配問題),但卻沒有解決設備 尺寸大小匹配 的問題。(即屏幕尺寸匹配問題)。

注意:屏幕寬度和像素密度沒有任何關聯(lián)關系。

  • (2)使用像素作為計量單位,采用百分比布局。

    • 從上面案例看出,因為屏幕密度(分辨率)不一樣,所以不能用固定的px;因為屏幕寬度不一樣,所以要小心的用dp。

    • 因為本質上是希望使得布局組件在不同屏幕密度上顯示相同的像素效果,那么,之前是繞了個彎使用dp解決這個問題,那么到底能不能直接用px解決呢?當然是可以的。根據(jù)不同屏幕密度,控件選擇對應的像素值大小。解決方法是: 百分比適配。

    • 先說一下缺點
      使用像素作為計量單位的適配方式,應該能進行90%的適配了,但其 缺點 還是很明顯:

    1.由于實際上還是使用px作為長度的度量單位,所以和google的要求使用dp作為度量單位會有所背離
    2.必須盡可能多的包含所有分辨率,因為這個是使用這個方案的基礎,如果有某個分辨率缺少,將無法完成該屏幕的適配
    3.過多的分辨率像素描述xml文件會增加軟件包的大小和維護的難度

★ 1.以某一分辨率為基準,生成所有分辨率對應像素數(shù)列表

現(xiàn)在我們以320x480的分辨率為基準:

將屏幕的寬度分為320份,取值為x1x320,將屏幕的高度分為480份,取值為y1y480
然后生成該分辨率對應像素數(shù)的列表,如下圖:

[圖片上傳失敗...(image-73a0c6-1517901336150)]

找到基準后,是時候把其他分辨率補全了,以下是以1080x1920的分辨率為例:

[圖片上傳失敗...(image-68b96a-1517901336150)]

關于自動生成values文件夾,這里推薦兩個工具:
AndroidPixelDimenGenerator ,使用方式可以百度一下,這不是本文的重點。
② 張鴻洋大神寫的autolayout.jar這個工具,下載地址請點此 ,使用方法如下圖所示:

[圖片上傳失敗...(image-8564f0-1517901336150)]

★ 2.將生成像素數(shù)列表存放在res目錄下對應的values文件下,這個步驟上面的動態(tài)圖已經做了。

注意事項:

  • (1)對應分辨率的資源文件應放在res/values對應的文件夾中。比如分辨率為1920x1080的資源文件應放在res/values-1920x1080文件夾中。
  • (2)必須在默認values里面也創(chuàng)建對應默認lay_x.xml和lay_y.xml文件,只是單位是dp。如果默認values文件夾沒有(即沒有對應的分辨率、沒有對應dimen)就會報錯,從而無法進行屏幕適配。

[圖片上傳失敗...(image-679bd4-1517901336150)]

★ 3.根據(jù)UI設計師給出設計圖上的尺寸,找到對應像素數(shù)的單位,然后設置給控件即可。如下圖:

<FrameLayout >
    <Button
        android:layout_gravity="center"
        android:gravity="center"
        android:text="@string/hello_world"
        android:layout_width="@dimen/x160"
        android:layout_height="@dimen/y160"/>
</FrameLayout>


4.2.2.圖片資源適配
使得圖片資源在不同屏幕密度上顯示相同的像素效果。

  • 解決方案:提供備用位圖(符合屏幕尺寸的圖片資源)

  • 常見做法步驟如下:

    ★ 1.根據(jù)以下尺寸范圍針對各密度生成相應的圖片:(一套分辨率設計一套位圖資源

    [圖片上傳失敗...(image-855ae8-1517901336149)]

比如說,如果我們?yōu)?xxhdpi 設備生成了144144 px尺寸的圖片,就應該按照相應比例地為 hdpi、xhdpi 和 xxhdpi 設備分別生成 7272 px 、9696 px 和 192192 px 尺寸的圖片。

★ 2.將生成的圖片文件放在 res/ 下的相應子目錄中(mdpi、hdpi、xhdpi、xxhdpi),系統(tǒng)就會根據(jù)運行您應用的設備的屏幕密度自動選擇合適的圖片。

★ 3.通過引用 @drawable/id,系統(tǒng)都能根據(jù)相應屏幕的 屏幕密度(dpi)自動選取合適的位圖。

  • 注意事項:
    1.如果是.9圖或者是不需要多個分辨率的圖片,放在drawable文件夾即可。
    2.對應分辨率的圖片要正確的放在合適的文件夾,否則會造成圖片拉伸等問題。

  • 圖片資源適配的 缺點:
1\. 每套分辨率出一套圖,為美工或者設計增加了許多工作量

2\. 對Android工程文件的apk包變的很大

  • 稍微優(yōu)化一下:有沒有一種方法,保證屏幕密度適配,可以最小占用設計資源,使得apk包不變大(只使用一套分辨率的圖片資源)?下面我們就來介紹這個方法:
    只需選擇唯一一套分辨率規(guī)格的圖片資源。
    xhdpi 應該是首選。目前市面上最普遍的高端機的分辨率還多集中在720X1080范圍內(xhdpi),所以目前來看xhpdi規(guī)格的圖片資源成為了首選。

  • 動態(tài)設置屬性,做到完美適配:

    ① 給ImageView設置不同的ScaleType屬性會得到不同的顯示效果,一般情況下,設置為centerCrop能獲得較好的適配效果。
    ② 有些情況下,我們需要動態(tài)的設置控件大小或者是位置,比如說popwindow的顯示位置和偏移量等。這時我們可以動態(tài)獲取當前的屏幕屬性,然后設置合適的數(shù)值。

public class ScreenSizeUtil { 
    public static int getScreenWidth(Activity activity) { 
        return activity.getWindowManager().getDefaultDisplay().getWidth(); 
    } 
    public static int getScreenHeight(Activity activity) { 
        return activity.getWindowManager().getDefaultDisplay().getHeight(); 
    }
}

③.使用第三方的屏幕適配框架。
`


本文參考文章:

作者:AWeiLoveAndroid
鏈接:http://www.lxweimin.com/p/7aa34434ad4d
來源:簡書
著作權歸作者所有。商業(yè)轉載請聯(lián)系作者獲得授權,非商業(yè)轉載請注明出處。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,488評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,034評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,327評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,554評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,337評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,883評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,114評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 48,625評論 1 332
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,555評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,737評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 43,973評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,615評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,343評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,699評論 2 370

推薦閱讀更多精彩內容