1. 程式人生 > >Android螢幕適配之佈局設定(二)

Android螢幕適配之佈局設定(二)

書接上回,我們已經瞭解了一些關於適配的一些相關概念,接下來我們會了解一下,在設定佈局時我們應該注意的地方。

儘量不去設定具體的尺寸值。

為了確保佈局適應各種尺寸的螢幕,在保證功能實現的前提下,最好不要寫死一些尺寸,這樣的硬編碼,我們最好使用“match_parent”,”wrap_content”,”weight”這些不用指定具體的尺寸值的引數,這樣檢視就會根據自身需要的空間去充填。這樣就可以讓佈局去適應各種螢幕的尺寸,當螢幕有旋轉時也不會受到影響。

這裡我們重點說一下“weight”,用過LiearLayout的同學應該都知道這個是什麼意思,它是LinearLayout獨有的屬性,我們可以使用這個屬性對介面成比例的分配,當我們的佈局對比例有要求時,我們就可以使用這個屬性進行設定。

既然是成比例,肯定會有的一個比例的計算規則。為了縮短篇幅,我們直接給出計算公式(我們只給出橫向的,豎向類似):

控制元件寬度 = 控制元件的原有寬度 +((LinearLayout寬度 - (所有子控制元件寬度總和))/ 所有子控制元件的weight總和) × 控制元件的weight值

(LinearLayout()÷weight))×weight
比如我們現在有個的螢幕是 320x480,根佈局為LinearLayout,狂傲為”match_parent”,方向為橫向,其中有兩個Button ,A和B,且A,B的android:layout_width屬性為”match_parent”,weight屬性值為1,那麼根據公式,我們計算一下A的寬度:
A=320
+((320-(320+320))/2)*1 =320+(-160) *1 = 160

即整個佈局的一半;關於這個這裡不再細講,感興趣的同學可以去大神趙凱強的部落格去看一下。

千萬不要使用絕對佈局

絕對佈局裡東西都是限定死的,對我們適配極為不利,我們不要使用它,我們優先使用 RelativeLayout,LinearLayout

其中 RelativeLayout中的控制元件位置都是相對的,我們可以根據不同需求調整控制元件的位置,而LinearLayout 它其中的控制元件的方向都是線性的,對著這方面有要求的可以優先使用。

考慮Fragment的使用

關於這個可以參看我之前寫的,關於Fragment的內容希望會對大家有幫助

使用尺寸限定符

在Fragment裡已經介紹過尺寸限定符了,這裡再具體說一下。

為什麼要使用尺寸限定符

大家都知道,手機跟平板的尺寸差別很大,有的平板是手機的兩倍大小,當我們的應用需要在手機或者平板上執行時,同一個介面 在手機上顯示很好,但是到了平板就會奇醜無比,所以有時候我們會設計兩款佈局,分別在手機和平板顯示,但是我們又不想去寫兩個Activity,怎麼辦?這樣我就會用到尺寸限定符。

預設的 我們的佈局是放到 layout這個資料夾下,我們的應用執行時,只會從這個資料夾下載入佈局。 當我們希望不同大小的手機或者平板載入不同的佈局時,我們就會建立一些其它的檔案來放置佈局。一般的我們會使用尺寸限定符來命名這些資料夾,這些限定會跟在layout後面,並以“—”間隔,當然這寫限定符不僅適用於layout,也同樣適用於values,下面列舉兩種:

限定符 功能介紹
large 系統會在屬於較大螢幕(例如 7 英寸或更大的平板電腦)的裝置上選擇此佈局。系統會在較小的螢幕上選擇layout下的佈局。
sw600dp 佈局僅適用於最小寬度為 600 dp 的螢幕, 但 Android 版本低於 3.2 的裝置不支援此技術,原因是這些裝置無法將 sw600dp 識別為尺寸限定符,因此您仍需使用 large 限定符

比如我們現在有一款新聞app,當在小螢幕上時,只顯示新聞列表的單面板佈局,在大螢幕上時,在螢幕的左邊顯示列表,在螢幕的右邊顯示選中的新聞的具體內容 的雙面板佈局,如下:

  • res/layout/main.xml: 單面板佈局
  • res/layout-large/main: 多面板佈局
  • res/layout-sw600dp/main: 多面板佈局

其中後兩個檔案是一樣的,只是第二個是為了適配Android 3.2裝置,第三個是為了適配版本較低的Android裝置的。為了避免這種重複出現的佈局檔案,影響我們的維護,我們可以使用別名檔案,例如:

  • res/layout/main.xml,單面板佈局
  • res/layout/main_twopanes.xml,雙面板佈局

我們同時在layout下建立兩個佈局。如果有些經驗的Androider,應該知道我們一半引用不同解析度的資源,都會在不同values資料夾下,例如:values-hdpi;那麼這裡我們也會用類似的方法來飲用不同的佈局。

首先我們引用普通的佈局,也就第一個單面板佈局。

res/values/下建立layouts.xml

<resources>
    <item name="main_layout" type="layout">@layout/onepane</item>
</resources>

然後我們引用大屏的佈局

res下建立values-sw600dp資料夾,然後在該資料夾下建立layouts.xml:

<resources>
    <item name="main" type="layout">@layout/main_twopanes</item>
</resources>

類似的我們建立values-large/layout.xml

<resources>
    <item name="main" type="layout">@layout/main_twopanes</item>
</resources>

後兩個檔案內容相同,我們只是給main在不同的解析度下的佈局設定了一個別名。只要我們在引用佈局的時候引用的是 “main”,裝置就會動態的根據螢幕的解析度去載入不同的佈局。

螢幕方向限定符

上面我們只是限定了螢幕的大小,但是我們手機的橫豎屏顯示的內容也千差萬別,如何限制在不同解析度下的橫豎屏的顯示佈局呢?Android給我們提供了螢幕方向限定符:

限定符 功能介紹
land 橫屏,它可以跟尺寸限定符一起使用,例如 values-sw600dp-land
port 豎屏,它可以跟尺寸限定符一起使用,例如 values-sw600dp-port

類似的我們建立以下檔案:

res/values/layouts.xml:

<resources>
    <item name="main_layout" type="layout">@layout/onepane_with_bar</item>
    <bool name="has_two_panes">false</bool>
</resources>

res/values-sw600dp-land/layouts.xml:

<resources>
    <item name="main_layout" type="layout">@layout/twopanes</item>
    <bool name="has_two_panes">true</bool>
</resources>

res/values-sw600dp-port/layouts.xml:

<resources>
    <item name="main_layout" type="layout">@layout/onepane</item>
    <bool name="has_two_panes">false</bool>
</resources>

res/values-large-land/layouts.xml:

<resources>
    <item name="main_layout" type="layout">@layout/twopanes</item>
    <bool name="has_two_panes">true</bool>
</resources>

res/values-large-port/layouts.xml:

<resources>
    <item name="main_layout" type="layout">@layout/twopanes_narrow</item>
    <bool name="has_two_panes">true</bool>
</resources>

當我需要顯示兩個面板的時候,我們在Activity 的onCreate方法中,就可以去判斷

““java
public class ArticleActivity extends FragmentActivity {
int mCatIndex, mArtIndex;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mCatIndex = getIntent().getExtras().getInt("catIndex", 0);
    mArtIndex = getIntent().getExtras().getInt("artIndex", 0);

    //判斷我們是否需要載入雙面板
    if (getResources().getBoolean(R.bool.has_two_panes)) {
        finish();
        return;
    }
    ...

}
““

它的使用跟尺寸限定符類似,如果想細究請參看支援各種螢幕尺寸

使用 9Patch

相信很多人都會多少知道這個工具,它會將png的某些部分進行拉伸,這樣我們可以使用小一些的圖片拉伸以實現大圖片實現的效果。

這個工具在/SDK 安裝目錄/sdk/tools/ 目錄下,全名叫做:draw9patch。只要雙擊既可以啟動,我們把需要拉伸的圖片直接拖進去就OK,就像下圖:

左邊為原圖,右側為拉伸後的顯示效果;而左邊圖上的黑線是用來指示我們拉伸區域。雖然我們看來那些在圖片邊界的上的黑線很粗,其實它們只有1px,我們看到的是放大後的結果,在我們應用中,我們是看不到的。下面我們說一下,黑色色條的作用。

黑線位置 作用
左邊和上邊 代表拉伸的區域
右邊和下邊 代表padding區域,如果這張圖作為控制元件的背景,如果控制元件需要顯示文字等內容,則都是在右邊和下邊黑線標出的交叉區域,它的功能就是控制元件的padding屬性

下圖是對應的拉伸區域, 左側是拉伸和padding區域,右側為顯示效果:

這裡指示簡單做個示例,有什麼不明白的可以去問度娘或谷歌。

另外附上常見的尺寸限定符:

螢幕配置 限定符值 介紹說明
smllestWidth(最小寬度) swdp:中間的N代表最小的寬度值,例如我們上面寫過的sw600dp,其它例子:layout-sw700dp,vaues-sw800dp 當螢幕的最小尺寸為我們設定的N時,系統就會去載入帶有該字尾的資料夾下的相關的檔案資源。例如:我們上面設定的layout-sw600dp,如果這個資料夾下的佈局要顯示到螢幕上,那麼我們的螢幕的最小尺寸在任何時候都至少是600dp,不管這個600dp是螢幕的寬還是高。也就是說 當你所有螢幕的最小寬度都大於600dp時,螢幕就會自動到帶sw600dp字尾的資原始檔裡去尋找相關資原始檔
可用螢幕寬度 wdp:類似上面的swdp.例如:layout-w600,values-w800 它的功能跟上面的相似。 帶這樣字尾的資原始檔的資原始檔制定了螢幕寬度的大於Ndp的情況下使用該資原始檔,但它和swdp不同的是,當螢幕橫向縱向切換時,螢幕的寬度是變化的,以變化後的寬度來與N相比,看是否使用此資原始檔下的資源。
可用的螢幕高度 hdp:類似上面的wdp.例如:layout-h600,values-h800 這個字尾的使用方式和wdp一樣,隨著螢幕橫縱向的變化,螢幕高度也會變化,根據變化後的高度值來判斷是否使用hdp ,但這種方式很少使用,因為螢幕在縱向上通常能夠滾動導致長度變化,不像寬度那樣基本固定,因為這個方法靈活性不是很好,google官方文件建議儘量少使用這種方式。

本文參考以下文章:

Android官方文件:適配多種螢幕