開發AIR mobile應用時多設備上的顯示處理

移動設備關於顯示效果的問題尤其突出,分辨率、屏幕尺寸各異,處理起來相對比較麻煩,好在Adobe本身已進行了相關處理,它主要是根據3個DPI來進行相應處理的。(用 Google Android SDK 的 Project 中的draw 目錄默認也是按 low、medium、high 區分的,所以按3個DPI處理應該是比較正確的方法啦)。

 

 

相關資料:

Android手機分辨率基礎知識

手機屏幕技術淺述(TFT、SLCD、AMOLED、NOVA、IPS、ASV)

Adobe官方文 檔:在一個手機應用程序中支持多個屏幕大小和 DPI 值

爲多個屏幕大小創作移動 Flash 內容

Flex移動skin – 第2部分:處理不同的像素密度

Mobile Development: scaling content depending on the screen resolution

Define a mobile application and a splash screen   (適用於Flex SDK v4.6.0)

 

一、簡單小結

官方給出的解決方法主要有以 下3種:(殊途同歸:最終都是靠DPI定位的)

1. 使用自動縮放:(方便和確保像素精確的視覺保真度之間的一種折衷方法)

    設置 application 的 applicationDPI 屬性值爲某個DPI;

    只需要針對目標DPI值創建外觀和組件佈局;

    位圖需最好要有多個版本,使用 MultiDPIBitmapSource 類進行設置;

    css中不需要使用@media。

2. 不使用自動縮放:

    需要針對3個DPI來創建外觀或組件佈局或支持根據DPI動態調整的外觀和佈局;

    在css中通過@media分別設置3套值(主要要設置字體大小、內邊距)。

3. 自定義設備的DPI歸類:(無論是否自動縮放均可)

    編寫一個 extends RuntimeDPIProvider 的類;

    設置 application 的 runtimeDPIProvider 爲該類;

    該類 override get runtimeDPI 方法,然後在該方法中可以根據Capabilities.screenDPI、Capabilities.screenResolutionY 等自定義設備的DPI 屬於哪一個。

 

其他幾篇文章提供的思路:

1. 儘量根據%、stage.stageWidth、stage.stageHeight 來設置組件寬度、高度;

2. 如果一定要用絕對值,則最好使用物理單位(如inch、cm),然後將該值轉化爲像素。

3. 使用絕對值時,在分辨率較高的屏幕上,組件會顯得較小,此時可以根據分辨率計算比例來對組件進行縮放。

 

、UI設計要點

1. 圖標大小:

1) 類似置於狀態欄、標題欄位置的圖標,比較合適的大小分別爲24、32(似乎36更合適)、48px;

2) 另一套比 1) 稍大的圖標大小標準分別爲36、48、72px。

2. itemrenderer 的高度,查看SDK源碼得知其默認被處理爲44、66、88px,可以按此標準考慮應用的某些尺寸。(調試發現,實際輸出高度分別爲:52、72、104)


、與分辨率、DPI相關的API

Capabilities.screenResolutionX 設備的橫向分辨率,在移動設備該值通常是較小的那個,如480*800的480。

Capabilities.screenResolutionY 設備的豎向分辨率。

Capabilities.screenDPI 設備的實際DPI。

FlexGlobals.topLevelApplication.runtimeDPI 設備的近似DPI,只有160、240、320這3個值。

DPIClassification.DPI_160, DPIClassification.DPI_240, DPIClassification.DPI_320 160,240,320對應的常量。

FlexGlobals.topLevelApplication.applicationDPI 應用的DPI,如未指定,其值=runtimeDPI。

 

四、實踐記錄(FlashBuilder4.5.1 + Flex SDK4.5.1 +AIRSDK2.7)

1. 桌面環境調試mobile應用時,Capabilities.screenResolutionX, Capabilities.screenResolutionY 返回的值是當前PC的分辨率,此時如果需要用到這2個值時只能hardcode。

 

2. 如果 view 的 actionBarVisible=true,則標題欄在3個DPI下的高度會有所不同,DPI320下會比較高,此時可能會影響到這個view最底部的元素的可見度,另外navigationContent、actionContent的寬度也與DPI有關(1024*600 DPI160時點擊範圍略微有些小),所以最好不要使用標題欄,若使用則需要測試下view內容是否能完整顯示,要不然只能給整個view加上scroll(僅爲了這一點加的話似乎不太划算)。可以考慮做個仿真的標題欄。

 

3. 實測我的應用,之前開發時未指定 applicationDPI,主要以480*800 240DPI(目前Android設備市場主流)爲參考進行UI設置的,字體大小爲28px,在 3.7 inch 寸設備上看起來大小比較適中。

然後分別在不同分辨率和DPI下進行測試,除了 320*480 DPI160下由於字體過大無法顯示完整的整屏內容外,在其他設備上均顯示良好,當然在分辨率高於480*800的設備上,原剛好一屏的內容會顯得有些“營養不良” 。

指定 applicationDPI=240 之後再次測試,分辨率在 600*1024 及其以上的設備上時,由於其默認DPI被歸於160,所以字體等被縮小了,顯得有些過小,不太合適。

 

4. 我的應用最終所採用的方案,共有以下幾點(幾乎把能用的都用上了):

1) 不使用自動縮放;(自動縮放存在一些問題)

2) 自定義 extends RuntimeDPIProvider 類,改寫默認的 runtimeDPI 策略;

主要改寫之處:

a) 分辨率在600*1024以上的設備的DPI,默認情況下均近似爲160,而這些設備的物理尺寸相對大部分手機來說是絕對夠大的,所以將其改寫爲歸於 240之列;

b) Motorola 的幾款手機分辨率高於480*800,如 Atrix 4G,其分辨率爲540*960,實際DPI爲275,默認情況下被歸於240之列,但由於其物理尺寸並未明顯加大,導致應用的字體等看起來偏小,所以將其改寫爲歸於320之列。

注:Moto Atrix 4G真機下運行測試,發現所得到的screenDPI居然是240,其桌面模擬環境是275,於是自定義的RuntimeDPIProvider 還得略作調整。

3) 位圖資源按ldpi、mdpi、hdpi分別準備3套 (這個無論是否自動縮放均需要);

4) css中使用@media 設置fontsize;

5) 使用物理單位,設置時將其換算成pixels,主要用在需要固定高度的地方,如view的頂部、底部、某些item等;

6) 根據分辨率scale組件,主要用在彈出窗口的寬度設置上,當分辨率較高時適當加寬以保證較佳的顯示效果;

7) 自定義style屬性,將諸如高度、間距等既需要固定值又需要根據DPI調整的地方,以這種方式綁定到css中,通過@media方式設置其值。(查看SDK源碼發現其對Button組件icon的處理也是採用style方式實現的 所以還是得多爬爬源碼啊

8) 啓動時所顯示的圖片,如果在應用程序mxml文件裏通過 splashScreenImage 指定1個圖片的話(同時通過 splashScreenScaleMode 設置拉伸方式),則在某幾個分辨率下,圖片拉伸後的效果是欠佳的。

Flex移動skin – 第2部分:處理不同的像素密度Dynamic Splash Screen Improvements   中提到的方法經過實踐,無法通過編譯,可能是SDK(版本應該是4.6.0的)不同的緣故。根據文章提供的思路,目前我採用以下方法來解決:

注:FlexSDK v4.6.0中已經添加了 SplashScreenImage、SplashScreenImageSource,以下方法僅適用於 4.5.x 版本,當運行於 4.6.0 環境時,啓動界面會出現2次,第2次所顯示的圖片有點不正確,有空白出現這個問題MS是另外寫了個首頁導致的)。

a) 複製spark.preloaders.SplashScreen 爲1個新類,application 的 preloader 屬性設爲該新類,splashScreenScaleMode 屬性可用可不用(依賴於你對SplashScreen所進行的改動);

b) 新類相較於原SplashScreen類,主要改動 initialize() 方法中 if ("splashScreenImage" in info) 處,原 splashScreenImage 值是1個固定的圖片source,這裏要把它改成根據不同的dpi、分辨率來得到其圖片source,所以我在 if ("splashScreenImage" in info) 之前增加了獲取圖片source的邏輯,同時對 if ("splashScreenImage" in info) 這個語句也進行了相應修改,修改後的代碼片段示例如下:

public function initialize():void
{
    ...
    if (!info)
        return;

    // 以下是我增加的
    var runtimeDPIClass:Class = info["runtimeDPIProvider"];
    var runtimeDPIProvider:RuntimeDPIProvider = new runtimeDPIClass();
    buildSplashImage(runtimeDPIProvider.runtimeDPI);

    // 原if改爲如下
    // if ("splashScreenImage" in info)
    if (splashImage != null)
    {
        // 註釋掉以下5行
        /*var SplashImageClass:Class = info["splashScreenImage"]; 
        this.splashImage = new SplashImageClass();
        this.splashImageWidth = splashImage.width;
        this.splashImageHeight = splashImage.height;
        addChild(splashImage as DisplayObject);*/
        
        ...
}

// 根據不同的dpi獲取不同的圖片源
private function buildSplashImage(dpi:Number):void
{
    // 具體的圖片源邏輯主要通過類 MultiDPISplashScreen 的 getImageClass 方法中進行處理,這裏就不貼源碼了
    var splashImageClass:Class = new MultiDPISplashScreen().getImageClass(dpi);
    splashImage = new splashImageClass();
    if (splashImage != null)
    {
        splashImageWidth = splashImage.width;
        splashImageHeight = splashImage.height;
        addChild(splashImage as DisplayObject);		
    }
}
 

 

總之,Adobe 對開發mobile應用的支持還是很不錯的,本身提供的模擬器在調試UI方面比較完善,常見的設備均有,並且也可以自行添加,顯示效果與真機相仿,爲我們調試在不同設備的顯示效果提供了良好的支持。

另外,這個模擬器雖然只是提供了一個顯示屏幕和menu、back、search按鈕、旋轉屏幕功能,但也是因爲這樣使得它在PC上運行的速度較快,不像Android模擬器那樣耗資源。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章