XAML in Xamarin.Forms 基礎篇 電子書

XAML in Xamarin.Forms 基礎篇 電子書
XAML in Xamarin.Forms 基礎篇 電子書

Xamarin.Forms 快速入門 電子書

Xamarin.Forms 快速入門 電子書
Xamarin.Forms 快速入門 電子書

2017/05/15

使用 Xamarin.UIText 進行 Android 專案的UI自動化測試技巧

當我們需要使用 Xamarin.UITest 進行您所開發的 Xamarin.Android App 做到 UI 自動測試,當然,首先,我們需要先建立一個 UI 測試應用程式 專案,您可以參考下圖,選擇 Visual C# > Cross-Platform > UI 測試應用程式(Xamarin.UItest | 跨平台),接著輸入這個測試專案名稱,最後,點選 確定 按鈕。
UI 測試應用程式(Xamarin.UItest | 跨平台)
接著,我們需要在剛剛產生的專案之中,指定要測試的 Android 專案,這裡,您會遇到兩個情況。不論是哪種情況,都建議您要間 INTERNET 這個權限啟用。
今天是 2017.05.15,根據官方的文件,Running Android 6.0 Applications from the IDE 中的描述,若要在 Android 6.0 平台下進行 UI 自動化測試,必須要使用 ApkFile 與在這個方法內加入 APK 的路徑。不過,若我使用第一個方法,也就是使用:在測試專案內,把 Xamarin.Android 專案參考,加入到這個 UI 測試專案內,原則上,不論是在 Debug / Release 模式下,都可以正常進行 UI 自動化測試。(我這裡的環境是 Windows 10 專業版 + Visual Studio 2015 Enterprise 版本)
結論就是,只要將 Android 專案參考加入到 Xamarin UITest 專案內,無視您的 Android 版本,就可以直接進行 UI 自動測試了。
請您將 Xamarin.Android 專案設定成為預設起始專案

若您使用的是 Android 6.0 以下作業系統

例如 API Level 19 的手機或者模擬器,您可以在 AppInitializer.cs 檔案中,修改成為如下程式碼。
在這裡,我們將會使用預設的 PreferIdeSettings() 方法,也就是,總是使用 IDE 中的設定。另外,我們也使用了 EnableLocalScreenshots() 方法,啟用了 Xamarin.UITest 可以進行本地端裝置的螢幕截圖功能。
    public class AppInitializer
    {
        public static IApp StartApp(Platform platform)
        {
            if (platform == Platform.Android)
            {
                return ConfigureApp
                    .Android
                    .EnableLocalScreenshots()
                    .StartApp();
            }

            return ConfigureApp
                .iOS
                .StartApp();
        }
    }
之後,您需要將您的 Xamarin.Android 專案的加入到剛剛產生的 UI 測試應用程式(Xamarin.UItest | 跨平台)專案內的參考,如此,當您建置這個 UI 測試應用程式(Xamarin.UItest | 跨平台) 專案的時候,您的 Xamarin.Android 專案,則也會自動建置到最新版本。
至於 建置模式 您可以選擇 Release 或者是 Debug 模式皆可。
另外,請切換到您要測試的模擬器或者實體手機選項;為了方便做到 UI自動測試,若您是使用模擬器,建議您先將這個模擬器啟動,並且解開螢幕保護模式,而且,請將其他 Android 模擬器關閉起來。若您是要在實體手機上做 UI 自動測試,請將所有的 Android 模擬器都先關閉起來。
接著,請先滑鼠右擊 UI 測試應用程式(Xamarin.UItest | 跨平台) 專案,選擇 重建,當完成之後,您就可以在測試總管中,看到這些可以測試的選項。
此時,您可以使用滑鼠右擊您有興趣的測試名稱,接著,選取,執行選取的測試 項目。
最後,您會看到神奇的事情發生了,您的 Xamarin.Android 應用程式,便會佈署到您指定的 Android 裝置內,而且自動啟動,然後,就會根據您所設定測試腳本,進行 UI 自動化測試。
選擇與執行UITest
若您想要在這種模式下,啟用 Xamarin Test Recorder,此時,若您的建置模式為 Debug ,則,您會遇到這樣的錯誤訊息:Failed connecting to app: Mono Shared Runtime is not supported. This can be resolved by changing the project configuration or using a Release build. 。解決方式,就如何說明內容所述,請切換到 Release 模式下,就可以使用囉。

若您使用的是 Android 6.0 的作業系統

在這裡,我們將使用 Visual Studio for Android Emulator 中的 6.0 模擬器,做為測試標的。
請您將 AppInitializer.cs 檔案中,修改成為如下程式碼。
在這裡,我們將會使用 ApkFile() 方法,來指定我們要測試的專案來源,此時的來源,就是我們要測試的 APK 檔案。另外,我們也使用了 EnableLocalScreenshots() 方法,啟用了 Xamarin.UITest 可以進行本地端裝置的螢幕截圖功能。
        public static IApp StartApp(Platform platform)
        {
            if (platform == Platform.Android)
            {
                return ConfigureApp
                    .Android
                    .ApkFile("../../../XFUITest/XFUITest.Droid/bin/Release/com.vulcanlab.xfuitest.apk")
                    .EnableLocalScreenshots()
                    .StartApp();
            }

            return ConfigureApp
                .iOS
                .StartApp();
        }
關於 ApkFile() 方法的用法,有兩個要注意的地方。
首先,您需要切換建置模式到 Release 模式下,因為,在 Androd 6.0下, Xamarin.UITest 將必須關閉 使用共用執行階段 選項。
另外,您需要手動點選 Xamarin.Android 專案,選擇執行 封存 選項,將您的 Xamarin.Android 專案封存起來,如此,在您的 Xamarin.Android 專案目錄內,就會產生一個 APK檔案。
最後使用這樣的路徑 ../../../XFUITest/XFUITest.Droid/bin/Release/com.vulcanlab.xfuitest.apk,指定 APK 檔案的路徑。這個路徑的來源,您可以參考下圖:因為,Xmarin.UITest 的專案是位於標號1的位置,而封存起來的 APK 檔案是位於標號2的位置。所以,您有兩種選擇來輸入這個路徑,第一個就是使用絕對路徑,另外一個就是使用相對路徑,透過下圖,您就可以使用相對路徑指出封存起來的 APK檔案的相對路徑了。
UITestAPK路徑
若您沒有將 Xamarin.Android 執行封存,並且做 Code Sign 的動作,那麼,當您要進行所要進行的 UI 自動化測試,就會出現底下的錯誤訊息,Visual Studio 會告訴您,無法找到您所指定的 APK 檔案。
結果訊息:     SetUp : System.Exception : ApkFile does not exist: D:\Vulcan\GitHub\temp\XFUITest_LocalAndroid\XFUITest\XFUITest.Droid\bin\Release\com.vulcanlab.xfuitest.apk
接著,請先滑鼠右擊 UI 測試應用程式(Xamarin.UItest | 跨平台) 專案,選擇 重建,當完成之後,您就可以在測試總管中,看到這些可以測試的選項。
此時,您可以使用滑鼠右擊您有興趣的測試名稱,接著,選取,執行選取的測試 項目。
最後,您會看到神奇的事情發生了,您的 Xamarin.Android 應用程式,便會佈署到您指定的 Android 裝置內,而且自動啟動,然後,就會根據您所設定測試腳本,進行 UI 自動化測試。
選擇與執行UITest
最後,再度提醒您,根據最前面的說明,剛剛的操作部分,是根據官方文件說明,特別針對 Android 6.0 平台所作的相關設定與處理動作;不過,經過測試,似乎在 Android 6.0 平台下,也可以使用第一個步驟的方法來做到。

2017/05/14

跨平台App開發的UX/UI 設計時候的設計畫素與實際畫素

在這篇文章中,我們將要來研究如何設計頁面各 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
Facebook

取得手機螢幕的使用實際畫素與設計畫素大小

每個平台都有專屬的 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倍的圖片
UWP Windows 10 Mobile
底下螢幕截圖是在 NavigationPage 下的執行結果,您可以但到,在導航頁面中的可用 ContentPage 空間明顯變小了許多,因為,最上方有導航工具列佔據了。
UWP Windows 10 Mobile
當推出了導航抽屜面板,我們可以看到抽屜面板的寬度為 320 設計畫素
UWP Windows 10 Mobile

UWP Windows 10 Mobile 裝置二

這個裝置的解析度為 720x1280
放大率為 2
整個螢幕的設計畫素為 360x616
圖片部分,使用的 2 倍的圖片(橘色)
UWP Windows 10 Mobile
底下螢幕截圖是在 NavigationPage 下的執行結果,您可以但到,在導航頁面中的可用 ContentPage 空間明顯變小了許多,因為,最上方有導航工具列佔據了。
UWP Windows 10 Mobile
當推出了導航抽屜面板,我們可以看到抽屜面板的寬度為 320 設計畫素
UWP Windows 10 Mobile

Android 裝置一

這個裝置的解析度為 1080x1793
因為 Android系統最下方有實體按鍵區域佔據了一部分螢幕可用空間
放大率為 2.65
整個螢幕的設計畫素為 407x676
圖片部分,使用的 3 倍的圖片(綠色)
Android UX/UI
底下螢幕截圖是在 NavigationPage 下的執行結果,您可以但到,在導航頁面中的可用 ContentPage 空間明顯變小了許多,因為,最上方有導航工具列佔據了。
Android UX/UI
當推出了導航抽屜面板,我們可以看到抽屜面板的寬度為 343 設計畫素
Android UX/UI

Android 裝置二

這個裝置的解析度為 480x738
因為 Android系統最下方有實體按鍵區域佔據了一部分螢幕可用空間
放大率為 1.29
整個螢幕的設計畫素為 371x570
圖片部分,使用的 1.5 倍的圖片(紫色)
Android UX/UI
底下螢幕截圖是在 NavigationPage 下的執行結果,您可以但到,在導航頁面中的可用 ContentPage 空間明顯變小了許多,因為,最上方有導航工具列佔據了。
Android UX/UI
當推出了導航抽屜面板,我們可以看到抽屜面板的寬度為 306.8 設計畫素
Android UX/UI

iPhone 6+

這個裝置的解析度為 1242x2208
放大率為 3
整個螢幕的設計畫素為 414x736
圖片部分,使用的 3 倍的圖片(綠色)
iOS UX/UI
底下螢幕截圖是在 NavigationPage 下的執行結果,您可以但到,在導航頁面中的可用 ContentPage 空間明顯變小了許多,因為,最上方有導航工具列佔據了。
iOS UX/UI
當推出了導航抽屜面板,我們可以看到抽屜面板的寬度為 331 設計畫素
iOS UX/UI

iPhone 6

這個裝置的解析度為 750x1334
放大率為 2
整個螢幕的設計畫素為 375x667
圖片部分,使用的 2 倍的圖片(橘色)
iOS UX/UI
底下螢幕截圖是在 NavigationPage 下的執行結果,您可以但到,在導航頁面中的可用 ContentPage 空間明顯變小了許多,因為,最上方有導航工具列佔據了。
iOS UX/UI
當推出了導航抽屜面板,我們可以看到抽屜面板的寬度為 300 設計畫素
iOS UX/UI