在這篇文章中,我們將要來研究如何設計頁面各 UI 的尺寸與定位位置的方法。
這篇文章中所用到的範例專案,可以從 https://github.com/vulcanlee/xamarin-forms-develop-notes-example/tree/master/XFMeasureScreen 取得
在我們進行頁面UI視覺設計的時候,各種控制項在有些情況下,不是透過版面配置 (Layout) 來計算訂出所需要的寬度與高度,而是要由我們自己來訂出所需要的寬度與高度;可是,不論是甚麼平台的手機,都存在著不同尺寸的手機,例如:4.7" / 5" / 5.2" / 5.5" / 5.9" / 6.4" 等等,而同一種尺寸的手機也會有著 16:9 / 16:10 等不同比例尺寸,另外同一種尺寸的手機有會存在著不同解析度 1080x1920 / 720x1280 / 750x1334 等等,也就是說,在手機螢幕上,可以顯示出來的全部畫素數量。
因此,再進行手機畫面 UI/UX 設計的時候,將會顯得更加複雜,不過,在各個手機平台中,我們進行 UI/UX 設計的時候,用來定義控制項的尺寸,都是使用與視覺無關的畫素來進行設計,不同種類的手機,都會定義出他的放大比率;所以;在最後要將控制項顯示在手機螢幕上的時候,會將您指定的與裝置無關的畫素 乘以 放大倍率,就會得到最終控制項的真實會用到的寬度與高度的畫素大小。
在底下,我們指定一個矩形 BoxView 控制項,他的寬度與高度分別是 200x50 (單位是與裝置無關的畫素),若我們將 App 執行在具有三倍放大倍率的手機上,這個時候,這個 BoxView 控制項,將會以 600x150 (單位是 Pixel 畫素)來顯示在手機螢幕上。
<BoxView x:Name="boxview" WidthRequest="200" HeightRequest="50" Color="Red"
HorizontalOptions="Start" VerticalOptions="Start"/>
不過,對於圖片來說,就無法使用這樣的方式來處理,我們需要在開發過程中,提供同一個圖片,但是擁有不同放大倍率大小的圖片檔案到 Visual Studio 專案內。在這個測試專案中,我們在每個平台專案內( Android / iOS / UWP ) 分別提供了不同放大倍率的圖片。
因此,當應用程式在不同放大倍率的手機上執行的時候,系統會自動依據放大倍率的大小,並且參考這個 App 內提供同一個圖片但是不同放大倍率的圖片,選擇出一個最適合的圖片來(這裡,我們並不需要做任何人為控制)。
但是,要提供同一個圖片,但是具有不同放大倍率的圖片檔案,每個平台的做法都不太一樣,有些是使用目錄名稱來區分,有些是依據檔案的特殊命名規則來區分,有些是兩者都可以;這部分的定義,請您去了解不同平台的 UX 設計規範文件,裡面將會有相當詳細的說明。
下圖是加入到 UWP 專案內的同一個圖片,但是具有不同的放大倍率;為了要能夠區分出不同放大倍率的圖片,我們使用了不同的顏色作為代表,這樣,當我們要進行測試的時候,就會知道當時所顯示的圖片,是採用放大幾倍的圖片。
在下圖中,從最左邊往右分別是
- 1倍圖片(藍色) : 50x50
- 1.5倍圖片(藍色) : 75x75
- 2倍圖片(藍色) : 100x100
- 3倍圖片(藍色) : 150x150
- 4圖片(藍色) : 200x200
取得手機螢幕的使用實際畫素與設計畫素大小
每個平台都有專屬的 API 可以讓您做到這樣的事情,另外,也可以得到這支手機的設計尺寸放大倍率值,底下分別針對三個平台說明如何使用這些 API 的作法。
一旦專屬平台下取得了螢幕實際畫素與設計畫素大小和放大倍率,就會寫入到核心 PCL 專案內的支援類別 AppGlobal 內的相關靜態屬性之中;之後,在 XAML 就會透過 x:Static 延伸標記,將這些值顯示在螢幕上。
public static class AppGlobal
{
#region 這裡定義從原生那裏取得的螢幕尺寸與縮放比
/// <summary>
/// 這個裝置的螢幕寬度的設計畫素
/// </summary>
public static double DisplayScreenWidth = 0f;
/// <summary>
/// 這個裝置的螢幕高度的設計畫素
/// </summary>
public static double DisplayScreenHeight = 0f;
/// <summary>
/// 這個裝置的設計尺寸縮放比
/// </summary>
public static double DisplayScaleFactor = 0f;
/// <summary>
/// 這個裝置的螢幕寬度的實際畫素
/// </summary>
public static double PhysicalDisplayScreenWidth = 0f;
/// <summary>
/// 這個裝置的螢幕高度的實際畫素
/// </summary>
public static double PhysicalDisplayScreenHeight = 0f;
#endregion
}
Android
在 Android 平台下,請在 MainActivity 內加入這些程式碼。
#region 取得當時螢幕的相關尺寸
// 取得當時應用程式視窗的設計尺寸
AppGlobal.DisplayScreenWidth = (double)Resources.DisplayMetrics.WidthPixels / (double)Resources.DisplayMetrics.Density;
AppGlobal.DisplayScreenHeight = (double)Resources.DisplayMetrics.HeightPixels / (double)Resources.DisplayMetrics.Density;
// 取得縮放比率
AppGlobal.DisplayScaleFactor = (double)Resources.DisplayMetrics.Density;
// 取得當時應用程式視窗的實際畫素
AppGlobal.PhysicalDisplayScreenWidth = (double)Resources.DisplayMetrics.WidthPixels;
AppGlobal.PhysicalDisplayScreenHeight = (double)Resources.DisplayMetrics.HeightPixels;
#endregion
iOS
在 iOS 平台下,請在 AppDelegate.FinishedLaunching 內加入這些程式碼。
#region 取得當時螢幕的相關尺寸
// 取得當時應用程式視窗的設計尺寸
AppGlobal.DisplayScreenWidth = (double)UIScreen.MainScreen.Bounds.Size.Width;
AppGlobal.DisplayScreenHeight = (double)UIScreen.MainScreen.Bounds.Size.Height;
// 取得縮放比率
AppGlobal.DisplayScaleFactor = (double)UIScreen.MainScreen.Scale;
// 取得當時應用程式視窗的實際畫素
AppGlobal.PhysicalDisplayScreenWidth = (double)UIScreen.MainScreen.Bounds.Size.Width* AppGlobal.DisplayScaleFactor;
AppGlobal.PhysicalDisplayScreenHeight = (double)UIScreen.MainScreen.Bounds.Size.Height* AppGlobal.DisplayScaleFactor;
#endregion
UWP
在 UWP 平台下,請在 App.OnLaunched 內加入這些程式碼。
#region 取得當時螢幕的相關尺寸
// 取得當時應用程式視窗的設計尺寸
AppGlobal.DisplayScreenHeight = Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().VisibleBounds.Height;
AppGlobal.DisplayScreenWidth = Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().VisibleBounds.Width;
// 取得縮放比率
AppGlobal.DisplayScaleFactor = Windows.Graphics.Display.DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel;
// 取得當時應用程式視窗的實際畫素
AppGlobal.PhysicalDisplayScreenHeight = Windows.Graphics.Display.DisplayInformation.GetForCurrentView().ScreenHeightInRawPixels;
AppGlobal.PhysicalDisplayScreenWidth = Windows.Graphics.Display.DisplayInformation.GetForCurrentView().ScreenWidthInRawPixels;
#endregion
在不同平台,不同手機下,測試取得設計與實際畫素和縮放比率
我們將會使用最初提到的測試專案,分別在 UWP / Android / iOS 平台的不同放大比率模擬器中,看看執行的結果。在每個手機下,將會分別擷取三個螢幕畫面,這分別是單純的 ContentPage 下的相關畫素、NavigationPage 下的相關畫素、導航抽屜的抽屜面板的寬度相關畫素。
您也可使用這個範例專案,在不同的裝置下來執行,看看所跑出來的結果為何?
UWP Windows 10 Mobile 裝置一
這個裝置的解析度為 1080x1920
放大率為 2.5
整個螢幕的設計畫素為 432x744
圖片部分,使用的 3 倍的圖片(綠色)
因為沒有2.5倍的圖片,因此,系統會使用較高放大倍率的圖片,再透過縮小演算法,將圖片縮小成為 2.5倍的圖片
底下螢幕截圖是在 NavigationPage 下的執行結果,您可以但到,在導航頁面中的可用 ContentPage 空間明顯變小了許多,因為,最上方有導航工具列佔據了。
當推出了導航抽屜面板,我們可以看到抽屜面板的寬度為 320 設計畫素
UWP Windows 10 Mobile 裝置二
這個裝置的解析度為 720x1280
放大率為 2
整個螢幕的設計畫素為 360x616
圖片部分,使用的 2 倍的圖片(橘色)
底下螢幕截圖是在 NavigationPage 下的執行結果,您可以但到,在導航頁面中的可用 ContentPage 空間明顯變小了許多,因為,最上方有導航工具列佔據了。
當推出了導航抽屜面板,我們可以看到抽屜面板的寬度為 320 設計畫素
Android 裝置一
這個裝置的解析度為 1080x1793
因為 Android系統最下方有實體按鍵區域佔據了一部分螢幕可用空間
放大率為 2.65
整個螢幕的設計畫素為 407x676
圖片部分,使用的 3 倍的圖片(綠色)
底下螢幕截圖是在 NavigationPage 下的執行結果,您可以但到,在導航頁面中的可用 ContentPage 空間明顯變小了許多,因為,最上方有導航工具列佔據了。
當推出了導航抽屜面板,我們可以看到抽屜面板的寬度為 343 設計畫素
Android 裝置二
這個裝置的解析度為 480x738
因為 Android系統最下方有實體按鍵區域佔據了一部分螢幕可用空間
放大率為 1.29
整個螢幕的設計畫素為 371x570
圖片部分,使用的 1.5 倍的圖片(紫色)
底下螢幕截圖是在 NavigationPage 下的執行結果,您可以但到,在導航頁面中的可用 ContentPage 空間明顯變小了許多,因為,最上方有導航工具列佔據了。
當推出了導航抽屜面板,我們可以看到抽屜面板的寬度為 306.8 設計畫素
iPhone 6+
這個裝置的解析度為 1242x2208
放大率為 3
整個螢幕的設計畫素為 414x736
圖片部分,使用的 3 倍的圖片(綠色)
底下螢幕截圖是在 NavigationPage 下的執行結果,您可以但到,在導航頁面中的可用 ContentPage 空間明顯變小了許多,因為,最上方有導航工具列佔據了。
當推出了導航抽屜面板,我們可以看到抽屜面板的寬度為 331 設計畫素
iPhone 6
這個裝置的解析度為 750x1334
放大率為 2
整個螢幕的設計畫素為 375x667
圖片部分,使用的 2 倍的圖片(橘色)
底下螢幕截圖是在 NavigationPage 下的執行結果,您可以但到,在導航頁面中的可用 ContentPage 空間明顯變小了許多,因為,最上方有導航工具列佔據了。
當推出了導航抽屜面板,我們可以看到抽屜面板的寬度為 300 設計畫素