提供可選的替代資源
乎每個應用程式都應該提供可選的替代資源,來支援特殊的裝置配置。例如,應該針對不同的螢幕解析度來包含可選的可描畫資源,並且為不同的語言環境提供可選的字串資源。在運行時,Android系統會檢測當前裝置配置,並給應用程式載入合適的資源。
以下是給特殊配置指定一組可選資源的步驟:
1. 用<resources_name>-<config_qualifier>的格式在res/目錄中建立一個新的目錄,<resources_name>是對應的預設資源的目錄名(表1中定義的);<qualifier>是給使用這些資源的裝置所指定的一個單獨配置的名字(表2中定義的)。每個名稱可以用短劃線來添加多個<qualifier>
警告:在添加多個限定符時,必須按照表2中列出的順序來放置它們。如果限定符的順序錯了,資源就會被忽略。
2. 在這個新的目錄中分別儲存可選的替代資源。這些資源檔必須像預設資源檔一樣被準確的命名。
例如,以下是預設和可選資源的定義:
res/
drawable/
icon.png
background.png
drawable-hdpi/
icon.png
background.png
hdpi限定符指示這個目錄中資源是給高解析度螢幕使用的。每個可描畫目錄中圖片都是為特定解析度的螢幕準備的,但是它們的檔案名稱是完全相同的。這樣用於引用icon.png和background.png圖片的資源ID就會相同,Android系統會通過裝置配置資訊和資來源目錄名中的限定符的比較結果,來選擇跟當前裝置匹配最好的資源版本。
Android支援幾種配置限定符,並且可以在一個目錄名中通過用短劃線的分隔,來添加多個限定符。表2按照優先的順序列出了有效配置限定符,如果要在資來源目錄中使用多個限定符,一定要按照表2列出的順序把它們添加到目錄名中。
表2.配置限定符名稱
| 配置 |
限定符值 |
說明 |
| MCC和MNC |
例如: mcc310 mcc310-mnc004 mcc208-mnc00 等 |
MCC是移動國家代碼的英文首字母縮寫(The mobile country code),它的後面可選擇性的跟隨來自裝置內的SIM卡的移動網路代碼(MNC:mobile network code)。如在任何載體上,mcc310代表美國,mcc310-mnc004代表美國的Venizon公司,mcc208-mnc00代表法國的Orange公司。 如果裝置使用音頻串連(GSM 電話),那麼MCC和MNC的值來自SIM卡。 也可以單獨使用MCC(例如,在應用程式中包含特殊國家合法的資源)。如果僅需要指定語言環境,那麼可以使用language和region限定符來替代(稍後討論)。如果決定要使用MCC和MNC限定符,就要仔細測試,使它能夠滿足你所期望的工作。 還可以查看佈建網域mcc和mnc,它們分別指示了當前的移動國家代碼和移動網路代碼。 mcc:http://developer.android.com/reference/android/content/res/Configuration.html#mcc mnc:http://developer.android.com/reference/android/content/res/Configuration.html#mnc |
| 語言和地區 |
例如: en fr en-rUS fr-rFR fr-rCA |
語言是用兩個字母的ISO 639-1語言代碼定義的,緊跟其後的是可選的兩個ISO-3166-1-appha-2地區代碼字母(前面是小寫“r”)。 這個編碼不區分大小寫,r首碼被用於區分地區部分,不能夠單獨指定地區。 如果使用者改變了系統中的語言設定,那麼在應用程式的運行期間也能夠改變為對應的語言。 |
| 最小寬度 |
sw<N>dp 例如: sw320dp sw600dp sw720dp 等 |
螢幕的基本尺寸,是指最短的可用螢幕地區。具體的說,裝置的最小寬度是螢幕可用的寬度和高度中最短的那個(也可以把它看做是螢幕的最小可能的寬度)。這樣就可以使用這個限定符來確保應用程式至少有<N>dp的寬度可用於UI介面,而不管螢幕的當前方向。 例如,如果布局在任何時候都需要至少600dp的最小螢幕尺寸,那麼就能夠使用這個限定符,在res/layout-sw600dp/目錄中建立布局資源。系統只會在可用螢幕的尺寸至少是600dp的時候才會使用這些資源,而不管600dp是否是被使用者認知的高度或寬度。最小寬度是裝置的固定螢幕尺寸特徵,當螢幕的方向發生改變時,裝置的最小寬度不改變。 裝置的最小寬度需要考慮螢幕的裝飾和系統UI的佔用。例如,如果裝置有一些固定的UI元素要沿著最小寬度的軸向,佔用一定的螢幕空間,那麼系統聲明的最小寬度要比實際的螢幕尺寸要小,因為被系統佔用的像素部分對使用者應用程式的UI無效。因此,這個值應該是應用程式布局所需要的最小的實際尺寸(通常,這個值是布局支援的最小寬度,而不管螢幕的當前方向)。 以下是可以使用的通用螢幕尺寸的一些值: 1.320,針對以下螢幕配置的裝置: 240x320ldpi(QVGA手持功能) 320x480mdpi(手持功能) 480x800hdpi(高解析度手持功能) 2.480,針對480x800mdpi的螢幕(平板或手持功能) 3.600,針對600x1024mdip的螢幕(7英寸平板) 4.720,針對720x1280mdip的螢幕(10英寸平板) 當應用程式提供了多個帶有不同值的最小寬度限定符資來源目錄時,系統會使用最接近(不超出)裝置最小寬度的那個資源。 這個限定符被添加在API層級13中。 還要看android:requiresSmallestWidthDp屬性,它聲明了與你的應用程式相容的最小的最小寬度,並且smallestScreenWidthDp配置欄位會持有這個裝置最小寬度的值。 |
| 可用寬度 |
w<N>dp 例如: w720dp w1024dp 等 |
指定最小的可用螢幕寬度,在資源中應該以dp為單位來定義<N>的值。當方向在橫向和縱向之間改變時,這個配置值會跟當前的實際的寬度相匹配。 當應用程式給這個配置提供了多個不同值的資來源目錄時,系統會使用最接近(不超過)裝置當前螢幕寬度的那個配置。這個值需要考慮螢幕裝飾佔據的空間,因此,如果裝置在顯示的左邊或右邊有一些固定的UI元素,那麼使用的寬度值就要比實際的螢幕尺寸小,因為這些固定UI元素的佔用,使得應用程式的可用空間減少。 這個特性被添加在API層級13中 還要看screenWidthDp配置欄位,它持有當前的螢幕寬度。 |
| 可用高度 |
h<N>dp 例如: h720dp h1024dp 等 |
指定最小的可用螢幕高度,在資源中應該以dp為單位來定義<N>的值,當方向在橫向和縱向直接改變時,這個配置值應該跟當前的實際高度匹配。 當應用程式給這個配置提供了不同值的多個資來源目錄時,系統會使用最接近(不超過)裝置當前螢幕高度的那個配置。這個要考慮螢幕裝飾的佔用情況,因此,如果裝置在顯示的上方或底部有一些固定的UI元素,那麼要使用的高度值要比實際的螢幕尺寸小,因為這些固定UI元素的佔用,使得應用程式的可用空間減少。不固定的螢幕裝飾(如電話的狀態列能夠在全屏時被隱藏)是不考慮的,像標題列或操作欄這樣的視窗裝飾也不考慮,因此應用必須準備處理比它們指定的空間要小的情況。 這個限定符被添加在API層級13中。 還要看screenHeightDp配置欄位,它持有當前螢幕的高度。 |
| 螢幕尺寸 |
small normal large xlarge |
small:這種屏類似低解析度的QVGA螢幕。對於小屏的最小布局尺寸大約是320x426dp。例如QVGA低解析度和VGA高解析度。 normal:這種屏類似中等解析度的HVGA螢幕。對於普通螢幕的最小布局尺寸大約是320x470dp。如,WQVGA低解析度屏、HVGA中等解析度屏、WVGA高解析度屏。 large:這種屏類似中等解析度的VGA螢幕,對於大螢幕的最小布局尺寸大約是480x640dp。例如VGA和WVGA的中等解析度屏。 xlarge:這種屏被認為比傳統的中等解析度的HVGA螢幕大。針對xlarge屏的最小布局尺寸大約是720x960dp。在大多數情況下,這種超大螢幕的裝置因為太大而要放到背包中來攜帶,而且最有可能的是平板樣式的裝置。 注意:使用尺寸限定符不意味著資源僅用於這個尺寸的螢幕。如果沒有用限定符提供與當前裝置配置相匹配的可選資源,那麼系統會使用與配置最接近的資源。 警告:如果所有使用尺寸限定符的資源都比當前螢幕大,那麼系統將不會使用它們,並且應用程式會在運行時崩潰(例如,如果所有的布局都被標記了xlarge限定符,而裝置卻是一個普通尺寸的螢幕)。 這個限定符被添加在API層級4以後的版本中。 |
| 螢幕外觀 |
long notlong |
long:長螢幕,如WQVGA、WVGA、FWVGA notlong:非長螢幕,如QVGA、HVGA、VGA 這個限定符被添加在API層級4以後的版本中 這個限定符完全是基於螢幕的外觀比率,不相對螢幕的方向。 還要看screenLayout配置欄位,它指示了螢幕是否是長屏。 |
| 螢幕方向 |
port land |
port:縱向裝置(垂直) land:橫向裝置(水平) 如果使用者旋轉螢幕,這個限定能夠在應用程式運行期間改變。 orientation配置欄位指示當前裝置的方向。 |
| 泊位元模式 |
car desk |
car:裝置停靠在汽車中 desk:裝置停靠在書桌中 這個限定符被添加在API層級8以後的版本中 如果使用者改變了裝置的停靠地點,那麼能夠在應用程式的運行期間改變這個限定。可以使用UiModeManager對象來啟用或禁止這種模式。 |
| 夜間模式 |
night notnight |
night:夜間 notnight:白天 被添加在API層級8以後的版本中 如果夜間模式被保留在自動模式中(預設),那麼在應用程式運行期間,會基於白天的時間來進行模式的改變。可以使用UiModeManager對象來啟用或禁止這種模式。 |
| 螢幕像素密度(dpi) |
ldpi mdpi hdpi xhdpi nodpi tvdpi |
ldpi:針對大約120dpi的低解析度螢幕; mdpi:針對大約160dpi的中等解析度螢幕(在傳統的HVGA上); hdpi:針對大約240dpi的高解析度螢幕; xhdpi:針對大約320dpi的超高解析度螢幕,被添加在API基本8以後的版本中; nodpi:這個限定被用於不想根據匹配的裝置解析度進行縮放的位元影像資源。 tvdpi:在mdpi和hdpi之間的螢幕,大約是213dpi。這種分組不是主要的解析度,大多數是為電視來考慮的,並且大多數應用不需要它---提供mdpi和hdpi資源就可以滿足大多數應用程式需要了,並且系統會適當的縮放它們。這個限定符在API層級13以後被引入。 四種主要的解析度之間的縮放比例是:3:4:6:8(忽略tvdpi解析度),因此一個9x9的ldpi位元影像,在mdpi中是12x12、在hdpi中是18x18、在xhdpi中是24x24。 如果感覺在電視或其他某些裝置上的圖片資源不好看,並且想要試用tvdpi資源,那麼縮放因子是1.33*mdpi。例如,一個100px x 100px的mdpi圖片的圖片應該被放大成133px x 133px的tvdpi圖片。 注意:使用解析度限定符不意味著資源僅適用與對應解析度的螢幕。如果沒有提供與當前裝置配置匹配的可選資源,那麼系統會使用最接近的資源。 |
| 觸屏類型 |
notouch stylus finger |
notouch:非觸屏裝置 stylus:有適用手寫筆的電阻屏裝置 finger:觸屏裝置 touchscreen配置欄位,指示到了裝置上的觸屏類型。 |
| 鍵盤可用性 |
keysexposed keyshidden keyssoft |
keysexposed:裝置有可用的鍵盤。如果裝置啟用了軟鍵盤,那麼即使在硬鍵盤沒有暴露給使用者時也可以使用這個限定符。如果沒有提供軟鍵盤或者軟鍵盤被禁用,那麼只有在硬鍵盤被暴露給使用者時才能夠使用這個限定符。 keyshidden:裝置有可用的硬鍵盤,但是被隱藏了,並且裝置沒有可用的軟鍵盤。 keyssoft:裝置有可用的軟鍵盤,不管它是否可見。 如果提供了keysexposed資源,但沒有keyssoft資源,那麼只要系統有可用的軟鍵盤,系統就會使用keysexposed資源而不管鍵盤是否可見。 如果使用者開啟了硬鍵盤,就可以在應用程式運行期間改變這個限定。 hardKeyboardHidden和keyboardHidden配置欄位分別指明硬鍵盤的可見度以及可見的鍵盤類型(包括軟鍵盤)。 |
| 主要文本IME |
nokeys qwerty l2key |
nokeys:裝置沒有用於文本輸入的硬鍵盤; qwerty:裝置有標準的硬鍵盤,不管使用者是否可見; 12key:裝置有12個鍵的硬鍵盤,不管使用者是否可見。 keyboard配置欄位指明可用的主要文本輸入方法。 |
| 導航鍵的有效性 |
navexposed navhidden |
navexposed:導航鍵對使用者可用; navhidden:導航鍵不可用。 如果使用者能夠看到導航鍵,那麼在應用程式運行時就能夠改變這個限定。 navigationHidden配置欄位,指示導航鍵是否隱藏。 |
| 主要的非觸屏導航方法 |
nonav dpad trackball wheel |
nonav:除了使用觸屏以外,裝置沒有其他導航設施。 dpad:裝置有用於導航的定向板(d-pad)。 trackball:裝置有用於導航的軌跡球。 wheel:裝置有用於導航的定向滾輪(不常見)。 navigation配置欄位指明可用的導航方法類型。 |
| 平台版本(API 層級) |
例如: v3 v4 v7 等 |
裝置支援的API層級。如v1代表API層級1(帶有Android1.0或更高版的裝置),v4代表API層級4(帶有Android1.6或更高版本的裝置) 警告:Android1.5和1.6隻有在限定符跟平台版本完全符合時,才能匹配資源。 |
注意:某些配置限定符從Android1.0開始就被添加了,因此不是所有的Android版本都支援所有的限定符。使用一個新的限定符,就隱含著添加了平台版本限定符,這樣舊的裝置才能夠保證忽略這個限定符。如使用w600dp限定符,將自動的包含v13限定符。因為有效寬度限定符在API層級13以後才支援。要避免一些問題的發生,就要始終包含一組預設的資源(這組資源沒有限定符)。
限定符命名規則
以下是有關使用配置限定符的命名規則:
1. 能夠給單一的資源集合指定多個限定符,限定符用虛線分開。例如,drawable-en-rUS-land指定資源要用於橫向的美式英語裝置。
2. 限定符必須按照表2列出的順序來使用,如:
錯誤用法:drawable-hdpi-port
正確用法:drawable-port-hdpi
3. 可選資來源目錄不能嵌套,如:不能用以下這樣的目錄結構:
res/drawable/drawable-en/
4. 值是大小寫敏感的。資源編譯器為了避免有關大小寫敏感的檔案系統問題,會把目錄名轉換成小寫。命名中的任何大寫字母只是為了方便閱讀。
5. 每個限定符類型只能支援一種資源值。例如,如果想對西班牙和法國使用同一個可描畫檔案,不能把目錄名命名成drawable-rES-rFR/。相反需要兩個目錄,如:drawable-rES和drawable-rFR/,每個目錄中包含對應的檔案。但是實際上不需要在這兩個目錄中複製相同的檔案,可以使用資源命名別名來解決,詳細請看下面的“建立資源別名”。
把這些可選資源儲存到這些帶有限定符的命名目錄中後,Android會基於當前的裝置配置在應用中自動的應用相應的資源。每次請求資源,Android都會檢查包含請求資源檔的可選資來源目錄,然後尋找最匹配的資源。如果沒有跟實際裝置配置匹配的可選資源,那麼,Android會使用相應的預設資源(不包含配置限定符的一組資源)。
給資源建立別名
當要給多種裝置配置使用同一個資源時(但不打算把這個資源作為預設資源),不需要把相同的資源放在多個可選資來源目錄中,相反,在某些情況下,能夠像儲存在預設資來源目錄中一樣給可選資源創一個別名。
注意:不是所有的資源都提供能夠建立一個指向另外一個資源的別名的機制。實際上,animation/、menu/、raw/以及xml/目錄中的非特定資源不提供這中功能。。
例如,假設有一個應用程式圖示:icon.png,它在不同的地區需呀唯一的版本。但是,有兩個地區,加拿大英語去和加拿大法語區,它們需要使用相同的版本。可以假設需要把相同的圖片分別複製到加拿大英語區和加拿大法語區的資來源目錄中,但實際上不需要這麼做。可以把使用icon_ca.png名字來儲存這張圖片(icon.png以外的任意名稱),並且把它放到預設的res/drawabel/目錄中,然後在res/drawable-en-rCA/和res/drawable-fr-rCA/目錄中建立一個cion.xml檔案,使用<bitmap>元素指向icon_ca.png資源。這樣就允許只儲存一個版本的PNG檔案,並且有兩個小的XML檔案指向它。
可描畫資源別名
使用<bitmap>元素,給一個既存的可描畫資源建立一個別名,例如:
?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/icon_ca" />
如果把這個檔案作為icon.xml來儲存在一個可選資來源目錄中,如res/drawable-en-rCA/,那麼它就會被編譯進能夠使用R.drawable.icon來引用的資源,但是實際上它是R.drawable.cion_ca資源的一個別名。
布局資源別名
使用封裝在<merge>元素中的<include>元素來給一個既存的布局建立別名,如:
<?xml version="1.0" encoding="utf-8"?>
<merge>
<include layout="@layout/main_ltr"/>
</merge>
如果把這個檔案儲存為main.xml,那麼它就會被編譯進能夠用R.layout.main來引用的一個資源,但是實際上它是R.layout.main_ltr資源的別名。
字串和其他簡單值的資源別名
只需簡單的使用被期望的字串的資源ID作為新的字串的值,就可以給一個既存的字串建立一個別名,如:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello</string>
<string name="hi">@string/hello</string>
</resources>
R.string.hi資源現在是R.string.hello資源的一個別名。
其他簡單的值資源也是用同樣的方法,如一個顏色值:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="yellow">#f00</color>
<color name="highlight">@color/red</color>
</resources>
摘自 FireOfStar的專欄