每一個 Windows Phone 7 應用程式在啟動時多少會花上一些時間,在這個等待的時刻經常都會擺放一些啟動畫面 (Splash screen) 先來充充場面,以免載入時間過長而導致使用者不耐煩,而在這個啟動畫面裡你還能藉此廣告一下把公司的 LOGO、連絡方式、品牌資訊都顯示在這個頁面裡,當然時間不能太長、也不能太短,否則若這個啟動畫面跑得太快,那就沒有出現的必要性了,有時後這種必要的「慢」也是一種藝術。在第一篇修練文章中,我們就從最基本的建立專案開始講起,在開始之前,請先閱讀 Windows Phone 7.5 (Mango) 開發學習資源整理 這篇文章設立基本的開發環境。
首先,我們先建立一個名為 WP7XiuLianDay1_SplashScreen 的專案:
我們選用 ”芒果機” 的作業系統:Windows Phone OS 7.1
開啟專案後,直接新增一個 Windows Phone Portrait Page 頁面,並取名為 SplashScreen.xaml
新增完頁面後直接在 XAML 設計檢視按下 Ctrl + A 全選,並將所有頁面上的視覺元素刪除
然後拉一個 Image 控制項進來
由於 Windows Phone 7 的螢幕大小目前都固定為 480 (寬) x 800 (高),而且我們希望這個啟動畫面能夠佔滿整個畫面,所以我們必須調整 Image 控制項的屬性,這是透過拖曳的方式並不精準,直接修改屬性會比較快些。
接著準備一張 480 x 800 的圖片(注意:不能使用 GIF 格式的圖檔),在此我的圖檔名為 SplashScreen.png 並用一個 Images 目錄來收納它。
然後再調整 Image 控制項的屬性,將圖片選進此控制項(意即設定 Source 屬性)
補充說明:我們也可以將 SplashScreen.png 圖檔的 Build Action 專案屬性從 Embedded Resource 調整為 Content,此舉的主要目的是為了降低 WP7 組件的大小,以加快整體應用程式的載入速度。
不過修改了圖檔的專案屬性後,你的 Image 控制項的 Source 屬性也要跟著調整,且必須調整為相對於專案根目錄的絕對路徑,用文字描述比較難懂,看圖吧:
此時,我們有了兩個頁面,分別是預設首頁 MainPage.xaml 與另一個啟動頁面 SplashScreen.xaml,如果你此時想要預覽剛剛設計的這個頁面的話,可能必須寫一些程式碼,才能把預設首頁自動轉向到這裡,我們先用「偷懶」的作法來實做頁面自動轉向功能。
先開啟 MainPage.xaml 的程式碼:
然後加上該頁面的 Loaded 事件,並透過 NavigationService 實做轉向功能
請注意:這是為了測試方便才這樣寫的,此寫法有 2 個嚴重的缺點:一個是頁面會先讓你看到 MainPage.xaml 然後才會進入到 SplashScreen.xaml 頁面裡;另一個問題是進入該頁面後,若按下手機的上一頁按鈕,又會繼續跳到 SplashScreen.xaml 這頁,這並非常規的設計法則,小朋友請不要亂學。
這時按下 F5 就可以立即看到 SplashScreen.xaml 頁面的出現,不過如果你的眼睛夠尖的話,可能會發現這張圖其實並沒有顯示的很完整,雖然你的圖片是 480x800 的大小,不過呈現在模擬器或手機裡時,其高度會被自動往下擠了 32px 的高度,也就是被 系統匣 (System Tray) 給佔用了!(如下圖示)
所以這張圖最下方的 32px 將會無法顯示在手機上,這一點其實在 XAML 設計檢視中也可以發現:
這時你可以有兩種抉擇,第一種是跟限制妥協,另外準備一張 480 x 768 的圖片來當 Splash 畫面(註:我不建議直接把圖片進行縮放,這樣圖片可能會稍微變形或失真)。
另一種方法,是透過設定把系統匣整個隱藏起來,如此以來便可將 480x800 的圖片完整的呈現在手機上,你可以直接修改 XAML 檔的設定,如下圖示把 shell:SystemTray.IsVisible 屬性調整為 False 即可。
另一種透過程式控制的方法可以在 SplashScreen.xaml 頁面 Code Behind 程式裡的建構子的最後面加入以下程式碼,就可以做到這個效果:
先引用 Microsoft.Phone.Shell 命名空間
using Microsoft.Phone.Shell;
再到頁面的建構子輸入以下程式
this.SetValue(SystemTray.IsVisibleProperty, false);
這時你再執行一次,比較一下跟剛剛的圖片是不是不一樣了呢?
目前我已經弄好一個 SplashScreen.xaml 頁面,當然,你也可以把這個頁面弄的很花俏,例如加上動畫或什麼的,但那不是本文章的重點,接下來就是本文的重頭戲,設計一個正規的應用程式啟動畫面。
我們之所以要做「啟動畫面」,目的可能有兩種:
- 因為應用程式需要初始化的時間太長,所以需要先顯示一個簡單的等待頁面。而這也是 Windows Phone Application Certification Requirements 的要求之一(請參見 Technical Certification Requirements 頁面的 5.2.1 Launch Time 這一條規則),而這也是學會設計啟動畫面如此重要的原因之一。
- 程式執行的太快,使用者沒有 feel,但要慢也要慢的優雅而從容。 XD
要讓 MainPage.xaml 正式開始執行之前,我們希望能先跳 SplashScreen.xaml 頁面出來,使用的技巧並不是先轉向到 SplashScreen.xaml 再轉回 MainPage.xaml 頁面,我們使用的技巧是透過一個 Popup 視窗擋住 MainPage.xaml 頁面,而這個 Popup 視窗裡就是包裹著 SplashScreen.xaml 頁面,以下是程式的寫法:
1. 先在 MainPage.xaml.cs 最上方引用以下命名空間
using System.Threading;
using System.Windows.Controls.Primitives;
using System.ComponentModel;
2. 然後宣告兩個類別層級的私有變數、修正建構子、並加上一個背景處理的方法。這段程式碼主要是在頁面尚未載入完成之前就先顯示一個 Popup 視窗,並設定在 3 秒之後自動關閉(秒數你可以自行調整):
BackgroundWorker backroungWorker;
Popup myPopup;
public MainPage()
{
InitializeComponent();
myPopup = new Popup() { IsOpen = true, Child = new SplashScreen() };
backroungWorker = new BackgroundWorker();
RunBackgroundWorker();
}
private void RunBackgroundWorker()
{
backroungWorker.DoWork += ((s, args) =>
{
Thread.Sleep(3000);
});
backroungWorker.RunWorkerCompleted += ((s, args) =>
{
this.Dispatcher.BeginInvoke(() =>
{
this.myPopup.IsOpen = false;
});
});
backroungWorker.RunWorkerAsync();
}
這時按下 F5 執行你會看到 SplashScreen.xaml 顯示 3 秒鐘後會自動關閉,但有趣的是,我們剛剛第一次顯示這個頁面時,這張 480x800 的圖的最下方被截掉了 32px 的空間,而這次透過 Popup 的方式卻是最上方的 32px 被截掉!(我覺得我可能是被客戶磨到成精了,盡是注意這些雞毛蒜皮的事 XD)
我們一樣套用剛剛學過的 Hack 技法,改寫這段程式碼,當我們顯示 Popup 頁面時 (SplashScreen.xaml) 關閉系統匣顯示,當關閉 Popup 頁面時再重新顯示系統匣,完整程式碼如下:
using System;
using Microsoft.Phone.Controls;
using System.Threading;
using System.Windows.Controls.Primitives;
using System.ComponentModel;
using Microsoft.Phone.Shell;
namespace WP7XiuLianDay1_SplashScreen
{
public partial class MainPage : PhoneApplicationPage
{
BackgroundWorker backroungWorker;
Popup myPopup;
public MainPage()
{
InitializeComponent();
myPopup = new Popup() { IsOpen = true, Child = new SplashScreen() };
backroungWorker = new BackgroundWorker();
RunBackgroundWorker();
this.SetValue(SystemTray.IsVisibleProperty, false);
}
private void RunBackgroundWorker()
{
backroungWorker.DoWork += ((s, args) =>
{
Thread.Sleep(3000);
});
backroungWorker.RunWorkerCompleted += ((s, args) =>
{
this.Dispatcher.BeginInvoke(() =>
{
this.myPopup.IsOpen = false;
this.SetValue(SystemTray.IsVisibleProperty, true);
}
);
});
backroungWorker.RunWorkerAsync();
}
}
}
今日修煉總結
今天我學到了如何有時後 GUI 介面不見得最方便,有時後手動修改 XAML 或調整屬性值比用圖形介面來拖曳來的方便。WP7 並不支援 GIF 圖檔(這是有專利的圖形格式),使用時應該避免使用 GIF 圖檔,否則看不到圖片你還會覺得是 WP7 的 Bug。也學到可以將 SplashScreen.png 圖檔的 Build Action 專案屬性從 Embedded Resource 調整為 Content,這樣可以降低 WP7 組件 (assembly) 的大小,以加快整體應用程式的載入速度。
除此之外,還學到了 WP7 手機一定會有個 系統匣 (System Tray) 顯示在頁面最上方,要完整顯示 480x800 的畫面則必須透過一些 Hack 技巧才能實現此功能。最後學到了如何正確的使用 Popup 類別來顯示啟動畫面,並透過 BackgroundWorker 的背景作業來設定固定時間後自動關閉啟動畫面。
相關連結