2015年7月5日 星期日

[擒猿基本功] Android app 支援多重螢幕

這個世界存在著許多各式各樣大大小小、長長扁扁、寬寬窄窄的智慧手機,它們佔據了現代人的生活模式、行為思考與社交聯繫,每台手機看似獨立運作,但其實它們內部都連結到了同一個虛擬世界,這個虛擬世界,我們稱之為安卓大陸。

是的,但今天沒有要寫擒猿記,而是要來寫 Android App 要如何支援多重螢幕,你一定覺得幹你娘很失望,沒關係,不要哭,堅強點。

Supporting Multiple Screens

根據 Android 官方文件,Android 定義了:
  • Screen size: 根據螢幕對角線長度定義 4 種 Size:
    • small
    • normal
    • large
    • xlarge
  • Screen density: 實體區域內的 dpi (dots per inch) 可想成是顯示品質,定義了以下 6 種:
    • ldpi (~120dpi)
    • mdpi (~160dpi)
    • hdpi (~240dpi)
    • xhdpi (~320dpi)
    • xxhdpi (~480dpi)
    • xxxhdpi (~640dpi)
實際螢幕大小與 Screen size、 Screen density 的關係圖如下,會有些許誤差:


Resolution 代表一個螢幕上實際的 pixel 點數,通常 app 不直接使用這個值,而是改用 dp (density-independent pixel),dp 為基於 160dpi 的螢幕 (medium 品質) 計算得到的 pixel 點數,通常 app 會利用這個值來定義 layout 長度,在 run-time 時 Android 系統則根據這個值與實際螢幕大小來做放大的動作,dp 與  pixel 轉換的公式如下:
px = dp * (dpi / 160)
舉例來說,在一個 240dpi 的螢幕上,layout中 1 dp 的長度表示在螢幕是實際顯示為 1.5 pixel 的長度。

支援多重螢幕的最高境就就是要達成 Density Independence,就是 user 在任何大小不同的螢幕上跑你的 app 看起來都一樣的。欲達成 Density Independence,定義 layout 長度時就不該使用 pixel 為單位,應該改用 dp,如此 Android 系統才能幫我們放大成最適合的大小,然而,系統放大的結果可能會導致 bitmap 圖片過於模糊,因此最好再根據不同解析度螢幕提供不同的圖片。

官方文件推薦以下幾種方式,能讓 Android 系統更有效處理多重螢幕的支援:
  1. 在 manifest 中指定 app 支援的 screen size
    • 在 manifest 利用 <supports-screens>  宣告可支援的 screen size,如此可以確保有在支援範圍內的裝置才能透過 Google Play 下載到這支 app。
  2. 為不同的 screen size 製作不同的 layout
    • 若需要對不同的螢幕的顯示方式做一些微調,則建議為其各自製作不同的 layout。
    • 不同的 layout 放置在不同的資料夾內,譬如 layout-xlarge/ 內放的就是給 extra-large螢幕顯示用的 layout,Android 系統根據 configuration qualifiers 的定義動態撈出需要的 layout 檔。
    • Android 3.2 (ApI Level 13) 之後應該使用 sw<N>dp 的形式來做更進階的分類,譬如放在 layout-sw600dp/ 資料夾內的 layout 檔案是給螢幕寬度至少 600dp 的裝置所使用。
  3. 為不同的 screen density 製作不同的 bitmap drawable
    • Android 系統會把 bitmap drawable (.png, .jpg, .gif, .9.png) 做放大的動作,若只放一種解析度的圖,則放大後可能會有變模糊的情況,因此最好為同一張圖製作多種解析度的副本。
    • Android 定義了 configuration qualifiers 讓不同解析度的圖可以放在不同資料夾下,譬如 drawable-hdpi/ 內放的圖就是給 high density 的裝置所使用。

如何使用 configuration qualifiers

Configuration qualifier 是一個字串可加在 resource 資料夾的名稱後方,協助 Android 系統分辨哪些 resource 是適合抓取來使用的。

在 Project 的 res/ 下依據不同解析度建立不同資料夾,然後把這些解析度的 layout 或 drawable 放入到對應的資料夾下,檔案名稱必須要跟 default 資料夾下放的一樣。

資料夾命名的格式如下:
<resources_name>-<qualifier>
resources_name 可以是 layout、drawable 等等 Android 的 standard resource
qulifiler 用來區分不同解析度的螢幕,填入值可以如下表格所定義:
Screen characteristic
Qualifier
Description
Size
small
Resources for small size screens.
normal
Resources for normal size screens. (This is the baseline size.)
large
Resources for large size screens.
xlarge
Resources for extra-large size screens.
Density
ldpi
Resources for low-density (ldpi) screens (~120dpi).
mdpi
Resources for medium-density (mdpi) screens (~160dpi). (This is the baseline density.)
hdpi
Resources for high-density (hdpi) screens (~240dpi).
xhdpi
Resources for extra-high-density (xhdpi) screens (~320dpi).
xxhdpi
Resources for extra-extra-high-density (xxhdpi) screens (~480dpi).
xxxhdpi
Resources for extra-extra-extra-high-density (xxxhdpi) uses (~640dpi). Use this for the launcher icon only, see note above.
nodpi
Resources for all densities. These are density-independent resources. The system does not scale resources tagged with this qualifier, regardless of the current screen's density.
tvdpi
Resources for screens somewhere between mdpi and hdpi; approximately 213dpi. 
Orientation
land
Resources for screens in the landscape orientation (wide aspect ratio).
port
Resources for screens in the portrait orientation (tall aspect ratio).
Aspect ratio
long
Resources for screens that have a significantly taller or wider aspect ratio (when in portrait or landscape orientation, respectively) than the baseline screen configuration.
notlong
Resources for use screens that have an aspect ratio that is similar to the baseline screen configuration.

Android 3.2 之後擴充了qulifiler 參數的使用,可以更詳細的利用 dp 還制定符合裝置的規格,避免遇到如 5" 和 7" 螢幕都是 large 的 screen size,無法為其制定不同的 layout 或 drawable,其新增的 qulifiler 使用方示如下:
Screen configuration
Qualifier values
Description
smallestWidth
sw<N>dp

Examples:
sw600dp
sw720dp
The fundamental size of a screen, as indicated by the shortest dimension of the available screen area. Specifically, the device's smallestWidth is the shortest of the screen's available height and width (you may also think of it as the "smallest possible width" for the screen). You can use this qualifier to ensure that, regardless of the screen's current orientation, your application's has at least <N> dps of width available for its UI.
Available screen width
w<N>dp

Examples:
w720dp
w1024dp
Specifies a minimum available width in dp units at which the resources should be used—defined by the <N> value. The system's corresponding value for the width changes when the screen's orientation switches between landscape and portrait to reflect the current actual width that's available for your UI.
This is often useful to determine whether to use a multi-pane layout, because even on a tablet device, you often won't want the same multi-pane layout for portrait orientation as you do for landscape. Thus, you can use this to specify the minimum width required for the layout, instead of using both the screen size and orientation qualifiers together.
Available screen height
h<N>dp

Examples:
h720dp
h1024dp
etc.
Specifies a minimum screen height in dp units at which the resources should be used—defined by the <N> value. The system's corresponding value for the height changes when the screen's orientation switches between landscape and portrait to reflect the current actual height that's available for your UI.

下列幾種歸類出來的qulifiler 可以快速對照使用:
  • 320dp: a typical phone screen (240x320 ldpi, 320x480 mdpi, 480x800 hdpi, etc).
  • 480dp: a tweener tablet like the Streak (480x800 mdpi).
  • 600dp: a 7” tablet (600x1024 mdpi).
  • 720dp: a 10” tablet (720x1280 mdpi, 800x1280 mdpi, etc).

如果還是不知道,請用密招,連機台下以下指令:
dumpsys window | grep dp
可以看到如下列結果:
mCurConfiguration={1.0 ?mcc?mnc en_US ldltr sw400dp w682dp h368dp 240dpi nrml long land finger -keyb/v/h -nav/h skin=/system/framework/theme-res-garmin.apk s.5}
因此針對該機台的 resources 應該放在 sw400dp 的 folder 底下。


Android 系統會預設去抓取最符合當前裝置的 layout 和 drawable,若找不到符合該定義的 resource 時才會去抓取 default 的 resource (不指定 configuration qualifiers 的 資料夾),或是利用一些邏輯判斷去抓取 "best matching" 的 resource。但當 Android 系統所找到的 resource 都比目前系統的定義要來的大時,Android 系統會拒絕使用這些 resource 而回報為 crash。

製作 Alternative drawables

在為不同大小螢幕製作各自的 drawable 時,必須遵守 3:4:6:8:12:16 scaling ratio 的原則,這是口訣,也是心法,譬如說有一張圖在 medium-density 的螢幕上為 48x48 pixels,則該張圖片的 alternative drawables 大小如下:
  • 36x36 (0.75x) for low-density
  • 48x48 (1.0x baseline) for medium-density
  • 72x72 (1.5x) for high-density
  • 96x96 (2.0x) for extra-high-density
  • 144x144 (3.0x) for extra-extra-high-density
  • 192x192 (4.0x) for extra-extra-extra-high-density (for launcher icon only)

1 則留言:

  1. Did you realize there's a 12 word sentence you can communicate to your man... that will trigger intense emotions of love and impulsive attraction to you buried inside his heart?

    That's because deep inside these 12 words is a "secret signal" that fuels a man's impulse to love, adore and guard you with his entire heart...

    ===> 12 Words Will Trigger A Man's Love Impulse

    This impulse is so built-in to a man's mind that it will make him try harder than ever before to to be the best lover he can be.

    In fact, fueling this dominant impulse is so mandatory to achieving the best ever relationship with your man that as soon as you send your man a "Secret Signal"...

    ...You'll immediately find him expose his soul and heart to you in such a way he never expressed before and he'll see you as the one and only woman in the universe who has ever truly understood him.

    回覆刪除