平台特色
在進行 Xamarin.Forms 跨平台應用程式開發的時候,由於,開發者會將大部分的商業邏輯與視覺介面都在核心PCL內進行開發,不過,有些時候在共用的商業邏輯程式碼內或者在共用視覺介面 XAML 定義宣告中,想是根據不同的平台與系統做出不同的反映;這樣的需求,就是這個章節存在的目的。
在這個章節內,開發者可以在核心PCL專案內,
- 得知使用者當時的裝置是 手機或平板或桌機 (使用
Device.Idiom
) - 依據使用者當時裝置的作業系統是 iOS/Android/WinPhone/Windows (使用
Device.OS
) - 在撰寫 XAML 內容時候,需要能夠針對不同的平台,提供不同的視覺效果 (使用
Device.OnPlatform
)` - 需要能夠使用類似 C#
Timer
定時器方法功能,Device.StartTimer
) - 最後,類似 WPF 開發方式,對於背景執行非同步執行續,有部分程式碼有更新UI內容,這個時候就可以使用
Device.BeginInvokeOnMainThread
建立標籤式的樣板式頁面方案
- 首先,開啟您的 Visual Studio 2015
- 接著透過 Visual Studio 2015 功能表,選擇這些項目
檔案
>新增
>專案
準備新增一個專案。 - 接著,Visual Studio 2015 會顯示
新增專案
對話窗,請在這個對話窗上,進行選擇Visual C#
>Cross-Platform
>Blank Xaml App (Xamarin.Forms Portable)
- 接著,在最下方的
名稱
文字輸入盒處,輸入XFDevice
這個名稱,最後使用滑鼠右擊右下方的確定
按鈕。 - 當專案建立到一半,若您的開發環境還沒有建置與設定完成 Mac 電腦與 Xamarin Studio for Mac 系統,此時會看到
Xamarin Mac Agent Instructions
對話窗出現,這個對話窗是要提醒您進行與 Mac 電腦連線設定,這是因為,您無法在 Windows 作業系統進行 iOS 相關應用程式的建立與設計工作,而是需要透過 Mac 電腦安裝的 XCode 來協助您完成這些 iOS 應用程式的建立工作。不過,這不影響您繼續開發 Xamarin.Forms 的應用程式,只不過此時,您無法編譯與執行 iOS 的應用程式。 - 接著會看到
新的通用Windows專案
對話視窗,此時,您只需要按下確定
按鈕即可,此時,專案精靈會繼續完成相關平台的專案建立工作。 - 最後,整個新的 Xamarin.Forms 專案就建立完成了。
MainPage
- 首先,打開核心PCL 的 MainPage.xaml 檔案,將底下的 XAML 宣告定義複製到這個檔案內。
- 在應用程式的首頁頁面, 首先使用了
ContentPage.Padding
來定義整個頁面的 Padding 範圍,會要這樣做的原因是,若 Xamarin.Forms 的 ContentPage 在 iOS 平台下執行的話,他會與最上方的狀態列互相重疊,如下圖所示,因此,需要特別針對 iOS 平台進行調整,避免發生這樣的情況。解決方案就是定義ContentPage.Padding
,在其裡面使用OnPlatform x:TypeArguments="Thickness"
分別指定個平台所需要的 Thickness 的值。 - 這個頁面的控制項,使用了
Grid
版面配置來進行所有控制項的定位。 - 在這個 XAML 範例內,關於
<OnPlatform ...> ... </<OnPlatform>
的使用方式,提供了不同的寫法,不論哪種用法,都具有同樣的效果。 - 當在
OnPlatform
內,使用了x:TypeArguments
指定所要客製化的物件值;若所要指定的物件屬於C#的基本型別,此時,您需要使用 XAML 標記延伸功能,使用x:
來指明所要設定的資料型別。
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XFDevice"
x:Class="XFDevice.MainPage"
Title="知道我在哪個平台上嗎?"
>
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<OnPlatform.iOS>
0,20,0,0
</OnPlatform.iOS>
<OnPlatform.Android>
0, 0, 0, 0
</OnPlatform.Android>
<OnPlatform.WinPhone>
0, 0, 0, 0
</OnPlatform.WinPhone>
</OnPlatform>
</ContentPage.Padding>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label
Grid.Row="0" Grid.Column="0">
<Label.Text>
<OnPlatform x:TypeArguments="x:String">
<OnPlatform.iOS>我正在使用 iOS</OnPlatform.iOS>
<OnPlatform.Android>我正在使用 Android</OnPlatform.Android>
<OnPlatform.WinPhone>我正在使用 WinPhone</OnPlatform.WinPhone>
</OnPlatform>
</Label.Text>
</Label>
<BoxView
Grid.Row="0" Grid.Column="1"
HorizontalOptions="Center" VerticalOptions="Center"
>
<BoxView.BackgroundColor>
<OnPlatform x:TypeArguments="Color"
iOS="Green"
Android="#738182"
WinPhone="Accent"
/>
</BoxView.BackgroundColor>
<BoxView.WidthRequest>
<OnPlatform x:TypeArguments="x:Double"
iOS="130"
Android="80"
WinPhone="30" />
</BoxView.WidthRequest>
<BoxView.HeightRequest>
<OnPlatform x:TypeArguments="x:Double"
iOS="130"
Android="80"
WinPhone="30" />
</BoxView.HeightRequest>
</BoxView>
<Label
x:Name="label處理中"
Text="處理中"
HorizontalOptions="Center" VerticalOptions="Center"
Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
/>
<Button
x:Name="button猜猜我是誰"
Text="猜猜我是誰"
HorizontalOptions="Center" VerticalOptions="Center"
Grid.Row="2" Grid.Column="0"
Clicked="OnGuessClicked" />
<Button
x:Name="button定時更新"
Text="定時更新"
Grid.Row="2" Grid.Column="1"
Clicked="OnTimerClicked" />
<Button
x:Name="button背景處理中"
Text="背景處理中"
Grid.Row="3" Grid.Column="0"
Clicked="OnBackgroundClicked" />
<Button
x:Name="button開啟網頁"
Text="開啟網頁"
Grid.Row="3" Grid.Column="1"
Clicked="OnOpenUriClicked" />
</Grid>
</ContentPage>
在 MainPage.xaml 的 code-behind 裡面,有定義了相關事件處理用法。
- 若想要在 C# 中針對不同平台執行不同的程式碼,此時,可以使用
Device.OnPlatform
這個方法,例如,在OnGuessClicked
按鈕事件方法內,根據不同作業系統與是否為平板或手機,傳回不同的字串,並且顯示在螢幕畫面上。 - 在核心PCL專案內,若想要使用 C# 的定時器功能 Timer, DispatcherTimer 這類功能,可以使用
Device.StartTimer
這個方法來取代;在這個方法內,若想要繼續下一個週期的定時執行,請回傳true
,若想要停止週期定時執行,請回傳false
。 - 最後,在
OnBackgroundClicked
這個事件處理方法內,說明了,當使用了非同步的背景執行時候,在背景運行程式碼內,想要更新 UI 內容的時候,您需要透過Device.BeginInvokeOnMainThread
這個方法,讓您相關更新 UI 內容的程式碼,在 UI 執行續內來執行。
MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace XFDevice
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
void OnGuessClicked(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();
Device.OnPlatform(
iOS: ()=>
{
sb.Append("嗯嗯嗯,您是 iOS, ");
},
Android: () =>
{
sb.Append("嗯嗯嗯,您是 Android, ");
},
WinPhone: () =>
{
sb.Append("嗯嗯嗯,您是 WinPhone, ");
}
);
sb.Append(Device.Idiom.ToString());
button猜猜我是誰.Text = sb.ToString();
}
void OnTimerClicked(object sender, EventArgs e)
{
int fooCC = 0;
int fooMax = 50;
Device.StartTimer(new TimeSpan(0, 0, 1), () => {
button定時更新.Text = $"{DateTime.Now}";
if (++fooCC > fooMax)
{
return false;
}
else
{
return true;
}
});
}
void OnBackgroundClicked(object sender, EventArgs e)
{
Task.Factory.StartNew(()=>
{
Device.BeginInvokeOnMainThread(() =>
{
label處理中.Text = $"處理中 現在時間:{DateTime.Now}";
});
});
}
void OnOpenUriClicked(object sender, EventArgs e)
{
Device.OpenUri(new Uri("http://www.xamarin.com"));
}
}
}
實際執行畫面
請再度重新執行,這個時候應用程式可以順利正常運行,螢幕截圖如下:
佈署注意事項
iOS 執行結果
請在方案總管內,滑鼠右擊
XFDevice.iOS
專案,選擇 設定為起始專案
,接著按下 F5
開始執行。