2014年9月9日 星期二

依解晰度選擇 Resource 與排版經驗

市面上愈來愈多筆記型電腦的螢幕採用高於 96 DPI 的規格,這代表著用戶雖然都是在 13 吋的機種下,卻顯示著長寬數量不同的 Pixel,這時如果兩種 DPI 下使用同樣的圖片來顯示,會導致在高 DPI 螢幕的環境下該圖被拉大至 140% 或 180% 甚至更高而產生模糊現像。

在使用 MFC、Win Form、WPF 開發應用程式時,介面比較不會使用 Modern UI ( Metro UI ) 來設計,所以對於 DPI 不同的影響較小,但在 Modern UI 的設計下,畫面大多是卡片與圖片或色塊式的內容,圖片的清晰度與卡片的顯示個數就是影響美觀程度的關鍵之一。

首先建立一個 Universal Apps 再看一下兩個平台專案的資料夾可以發現有趣的狀況,在 Windows Project 下 Logo 圖檔檔名為 Logo.scale-100.png,而在 Windows Phone Project 下 Logo 圖檔的檔名為 Logo.scale-240.png,後面的 100 及 240 代表著目前裝置的 DPI 對比預設 96 DPI 的比例。

以 Windows Phone Device 為例,早期的解晰度為 800*480 又稱 DPI 為 100%,在同樣的螢幕尺寸塞下 1920*1080 的 Pixel 時 DPI 就是原先的 240%,這種情況下應用程式會自動挑選檔名後有 .scale-240 的檔案來用,在 Windows 上也是一樣的邏輯,以下簡單的寫一個範例來看看效果。

先在專案中的 Assets 資料夾加入以下三張圖片




這三張的圖片分別為 100*100 與 140*140 與 180*180,中間的文字尺寸各是 24、34、44,接下來將 MainPage.xaml 的內容修改為

<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Image Source="Assets/demo.png" Stretch="None"/>
</StackPanel>

在 Windows 模擬器下運作時,在尺寸同為 10.6 吋下切換 1366*768、1920*1080 與 2560*1440 三種解晰度,可以看到雖然我們是寫 demo.png 但在切換解晰度造成 DPI 改變時,應用程式自動選擇了適當的圖片,而不是將灰綠色的圖片拉大造成模糊。

如果之前已經了解如何在 Windows RT 下取用 DPI 的開發者大概會發現有些 API 被標示為 deprecated 了,以下是 Store Apps 查詢 DPI 的方式。

const int DEFAULT_LOGICALPPI = 96;
const int PERCENT = 100;

private void OnPageLoaded(object sender, RoutedEventArgs e)
{
    float logicalDpiInDisplayProperties = DisplayProperties.LogicalDpi; // deprecated
    float logicalDpi = DisplayInformation.GetForCurrentView().LogicalDpi; // 96 or 134.4
    Debug.WriteLine((logicalDpi * PERCENT / DEFAULT_LOGICALPPI).ToString() + "%"); // 100% or 140%...
}

在 DisplayInformation 底下還有 Orientation 等資訊可以拿,也可以直接取用 ResolutionScale 拿到 DPI 的列舉值,而取得螢幕解晰度的方法是使用 Window.Current.Bounds 這個屬性,但需注意這個解晰度並不受 DPI 影響,它所顯示的是邏輯上的解晰度,所以如果想要拿到拿到實際的 Pixel 值,必須再自己乘上 DPI 值,以上面的 10.6 吋 1920*1080 的裝置為例,拿到的值如下。

private void OnPageLoaded(object sender, RoutedEventArgs e)
{
    DisplayInformation information = DisplayInformation.GetForCurrentView();
    float logicalDpi = information.LogicalDpi; // 134.4
    float percent = logicalDpi / DEFAULT_LOGICALPPI; // 1.4
    Double width = Window.Current.Bounds.Width; // 1371.4285888671875
    Double height = Window.Current.Bounds.Height; // 771.4285888671875

    // 解晰度:1371.42858886719 x 771.428588867188, 實際 Pixel:1919.99999171666 x 1080.00000602177
    Debug.WriteLine("解晰度:{0} x {1}, 實際 Pixel:{2} x {3}", width, height, width * percent, height * percent);

    // 簡單的 4 捨 5 入可得 "實際 Pixel:1920 x 1080"
    Debug.WriteLine("實際 Pixel:{0} x {1}", (Int32)(width * percent + 0.5), (Int32)(height * percent + 0.5));
}

目前市面上有兩種不同的排版方式,一種是畫面上的卡片數量不變,而是卡片的尺寸隨著螢幕放大或縮小,在不同的解晰度下看起來都是一樣的體驗,另一種是像 Windows 首頁或市集首頁一樣,依螢幕的 Bounds 來顯示不同個數的卡片,這種情況會導致卡片數過少時畫面過空的狀況,所以開發者若選擇這種排版方式,務必依 Bounds 計算必須拿多少資料來顯示,免得讓精心設計的畫面發生在某些 Bounds 下看起來空蕩蕩的現像。

補上官方文件:DisplayInformation


沒有留言:

張貼留言