最近研究了一下Android中的自動適配,加上Studio便捷的實時預覽功能,總結一下如何在Android Studio中快速方便適配多種螢幕。

先來補習一下基礎知識,來看幾個名詞解釋:

解析度整個螢幕的畫素數目,為了表示方便一般用螢幕的畫素寬度(水平畫素數目)乘以畫素高度表示,形如1280x720,反之解析度為1280x720的螢幕,畫素寬度不一定為1280

螢幕密度表示單位面積內的畫素個數,通常用dpi為單位,即每英寸多少個畫素點

px長度單位,以具體畫素為單位

dp長度單位,與具體螢幕密度無關,顯示的時候根據具體平臺螢幕密度的不同最終轉換為相應的畫素長度,具體轉換規則是: 1dp = (目標螢幕密度/標準密度)*px,標準密度為160dpi,例如,1dp長度在密度為160dpi的平臺表示一個畫素的長度,而在240dpi的平臺則表示1.5個畫素的長度

螢幕尺寸螢幕的大小,通常用螢幕對角線的長度表示,一般單位是inch

這些是最基本的概念,懂了這些,再來看Android中是如何來定義螢幕的大小的:

螢幕尺寸分為:small,normal,large,xlarge分別表示小,中,大,超大屏

螢幕密度分為:ldpi,mdpi,hdpi,xhdpi,它們的標準值分別是:120dpi160dpi240dpi320dpi

我們用一個圖來直觀地看一下


基本上3inch以下的歸為small,而normal據我通過Studio實際操作的到的結果是:幾乎3-6inch之間(不包括6inch)的都算是normal(除了個別5.x的WVGA屬於Large等個例),在後面的實際操作中我們還會進一步看到。

而螢幕密度其實也是和螢幕大小相對應的,一般來說,螢幕越大的,密度也越高。如果你非得說我的6英寸的大手機,解析度是800x600,那我的dpi也就160,那是可以的,但是那麼大的螢幕,解析度卻很低,這樣的裝置估計也沒人買單,所以,市場的主流也反映出來,螢幕密度越大,螢幕也相對來說要大一些。

好了,介紹完基礎知識,我們來看如何在Studio中完成多種裝置的螢幕適配。

我們開啟工程預設的Layout資料夾,然後選中一個XML佈局檔案,然後在Studio的右上角,我們能看到列出了很多裝置


我們能看到這裡面有各種各樣大小和密度的裝置。那我們知道在實際過程中,為了適配不同的螢幕,需要設定相應的XML資料夾(layout-normal,layout-large等),這樣程式在讀取到相應的裝置的時候,能自動去不同的資料夾中讀取。如果大家沒有設定,那我們的程式當前就只有一個預設的資料夾,叫做layout,來存放XML頁面佈局檔案,當然,我們的程式也就不能適配不同大小和DPI的裝置了。那我們就來建立相應的資料夾吧。


如上圖中的紅框所示,我們選擇Create Other...



在彈出的介面中,依次點中Size 和 >>


然後我們先選擇一個Normal來看一下效果吧


這個時候,在左側的導航欄,其實多了一個資料夾layout-normal,裡面自動複製了一份activity_my.xml檔案,並自動選中了當前的這個檔案,也就是如果我們接著編輯,就是對Normal尺寸大小的裝置的activity_my.xml檔案進行修改了,如果你點選右上角檢視裝置,會發現基本沒有什麼變化啊,但是其實不然,點選Generic Phones and Tablets按鈕,在彈出的更多的裝置中,我們能看到有兩個裝置前面打了x號,因為這兩個裝置是2.7inch的,之前我們也說過,3inch以下的裝置都是small型別的。

那有同學就有疑問了,那不可能剩下的所有裝置都是normal的啊?當然不是,但是因為我們現在已經對layout做了區分,但是還沒有分那麼細,所以Studio就預設“向下相容”了。

我們可以接著來創見一個layout-xlarge來試驗一下就ok了


我們看到Studio直接給我們提供了xlarge的選單選項,直接點選一下就OK了。


我們看到在左側導航欄又多出來一個資料夾 layout-xlarge,這下再來看裝置列表。基本上所有的裝置前面都是x了,只有少數幾個8,9inch的裝置被包含了進來,剩下的大部分還是處在normal資料夾中,而large的裝置(6-7inch之間)因為向下相容,換句話說,沒有資格進入到xlarge資料夾中,所以還是留在了normal資料夾中。

之前我們也說過,因為3-6inch的很多裝置都算是Normal的,那就很容易出現5.x英寸xxhdpi的裝置和3.7英寸hdpi的裝置都歸到normal檔案中


如上圖所示,Nexus One 和Nexus6P明顯裝置大小差很多,但是卻都屬於Normal的,所以就可能出現下面的情況


如上圖所示,我們添加了一個圖片,圖片的長寬都是300dp。

說到這裡我們再回顧一下吧,基本上有個定論大家都知道:

在XML檔案中控制元件的大小單位用dp,文字的大小單位用sp。

因為這樣子可以保證在不同的裝置上顯示同樣大小的控制元件;這裡說的同樣大小指的是控制元件的絕對大小,而dp單位設定的目的也就是如此。

而這樣就容易出現一個問題,就是因為螢幕尺寸的不同,導致同樣大小的控制元件在不同是螢幕下面顯示的相對大小發生很大的變化。

我們還是看個實際的例子吧。

上圖裡面300x300dp的圖片在Nexus One(3.7 inch)上面看起來比較和諧,在螢幕中間佔的位置也很合適,

但是在大一點的螢幕上面呢?


我們可以發現在Nexus 6(6 inch)裡面圖片相對於手機來說變小了。那因為Nexus One(3.7inch)和Nexus6(6inch)都屬於Normal範圍之內的,我們似乎不能通過設定不同的資料夾來處理的。

事實真的是這樣麼?

別忘記了我們還有不同的螢幕密度可以作為區分。

讓我們先清理一下layout系列檔案,刪除我們之前建立好的layout-normal和layout-large資料夾


用同樣的方法建立新的layout資料夾,只不過這次資料夾的名字是layout-normal-ldpi


同樣的方法再建立一個資料夾 layout-normal-mdpi

我們來看右側所有裝置的列表,當我們選中layout-normal-mdpi時,我們能看到有幾個裝置前面是x,也就是不屬於這個資料夾的,而我們也能看到他們屬於的資料夾的位置,圖中我用兩個紅圈表示了出來。

因為現在layout的資料夾只有3個:一個預設的layout,一個layout-normal-mdpi還有一個是layout-normal-ldpi,那我們能看到兩個2.7 inch的裝置是處在預設的layout資料夾中,而兩個雖說螢幕大小達到了normal,但是密度卻沒有達到mdpi的裝置則處在了layout-normal-ldpi資料夾中。

這裡同樣的,螢幕密度也符合上面說的“向下相容”的原則。因為我們還沒有建立比mdpi更高的螢幕密度,所以包括hdpi,xhdpi,xxhdpi等都放在當前的mdpi資料夾下面。


讓我們接著建立layout-normal-hdpi資料夾,可以看到有很多裝置從mdpi中移了出來,因為當前有了更適合他們呆的地方---hdpi


最後當我們建立好layout-normal-xhdpi之後,我們發現終於,兩個小螢幕但是密度是hdpi的裝置 Nexus S和Nexus One終於和上面的那些同樣是normal螢幕大小但是密度也大的裝置分離開來了。

這樣我們就能分開來調整介面了~


讓我們修改layout-normal-xhdpi資料夾下面的XML頁面佈局檔案,然後將圖片的大小改為400dp,在來看一下,同樣的Nexus 6 的螢幕 是不是看起來更和諧一點了?


這樣基本上我們就成功實現了對多裝置的支援。

總結下來:

1. Android Studio可以很方便地為我們建立多個資料夾,只需要選中想要完成多裝置適配的XML檔案,然後點選右上角的選單,建立自己想要實現的螢幕大小,就OK了,檔案就會自動被複制到相應的資料夾下面。

2. 在程式執行時,會自動尋找最接近當前螢幕大小分類的資料夾中的XML佈局檔案去顯示。

所以,之後再開發的話,我的步驟是:

1. 先建立4個不同的layout資料夾  layout-small, layout-normal, layout-large, layout-large,

2. 如果在開發過程中有遇到進一步適配(不同的DPI),就另外建立新的資料夾出來,因為即便同時有layout-normal和layout-normal-hdpi資料夾,當你的裝置是normal大小、高密度的螢幕時,也能自動顯示layout-normal-hdpi中的XML檔案,就是這麼智慧。

3. 雖然文中我舉的例子是用圖片,但是實際開發中,如果要新增的內容是圖片,就要在drawable資料夾下面做出不同裝置大小的分類了,然後在XML檔案中設定長寬分別是wrap-content;但是我們總會遇到要填充比如第三方控制元件的情況,那這種型別就不適用了。

4. 儘量用RelativeLayout來完成頁面的佈局,這樣子可以更好的做適配,相對佈局在大部分情況下比絕對佈局要容易很多

最後不知道同學們有沒有發現,Studio除了能動態實時地顯示不同的屏幕布局之外,還能夠在程式碼區的左側,實時地顯示你的資原始檔中的縮圖,就像上圖中ImageView的background一樣,在那一行程式碼的左側,能看到一個小的縮圖,顏色也是一樣,當你在程式碼中寫入#e0e0e0這樣的程式碼時,能自動顯示出來顏色呦,有沒有很舒服?

期待在使用的過程中,Studio帶給我們越來越多的surprise