An Introduction to Xamarin.Forms
來源:http://developer.xamarin.com/guides/cross-platform/xamarin-forms/introduction-to-xamarin-forms/
概覽
Xamarin.Forms 是一個幫助開發者快速創建跨平台UI的框架。它為ios,Android,Windows Phone上的原生控件的使用提供了一層抽象.這意味着應用程序之間可以共享大部分UI代碼,同時還能保持相應平台的界面外觀樣式。
Xamarin.Forms使用C#編寫,能夠適應於快速開發越來越復雜的應用程序。因為采用 Xamarin.Form的應用程序是原生應用程序,不必受制於其他類似開發工具包的限制,如瀏覽器沙箱, 有限的API,糟糕的性能. 使用 Xamarin.Forms編寫的程序能夠使用下層平台的任何API或者特性,包括但不限於CoreMotion, PassKit, and StoreKit 之於iOS; NFC 和Google Play Services 之於 Android; Tiles 之於 Windows Phone.這也意味着你可以開發一個應用程序部分使用 Xamarin.Forms創建的UI,部分使用原生 UI 開發包來編寫.
Xamarin.Forms 應用程序和傳統的跨平台應用的架構是一樣的。. 最常見的辦法是使用 Portable Libraries 或者 Shared Projects 來共享代碼, 然后創建平台相關的項目來消費使用共享代碼.
Xamarin.Forms使用兩種方式創建用戶界面。第一種是用Xamarin Forms提供的API直接在源代碼里創建UI,另一種可選的方法是使用 Extensible Application Markup Language (XAML),(一種MS用於定義界面的標記語言). 用戶界面將使用XAML定義在一個XML文件中,運行時的行為則被定義在單獨的代碼文件中。了解更多關於XAML,可以閱讀 XAML Overview 文檔 What is XAML.
本指南只是Xamarin Forms框架基礎,包含以下主題
- 安裝Xamarin.Forms.
- 在 Visual Studio 或Xamarin Studio中新建解決方案.
- 如何使用Xamarin.Forms中的頁面和控件
- 如何在頁面間導航
- 如何設置數據綁定
要求
Xamarin.Forms 應用程序可以運行在如下移動操作系統中:
- Android 4.0 或以上
- iOS 6.1 或以上
- Windows Phone 8 (使用Visual Studio)
Xamarin.Forms 為了部分控件(如DatePicker)需要要求安裝 Windows Phone Toolkit .
我們假定開發者已經熟悉 Portable Class Libraries 和Shared Projects用法
Mac 系統要求
在OSX上開發Xamarin.Forms程序需要安裝Xamarin Studio 5 . 開發iOS程序則要求安裝 Xcode 5 (操作系統要求 OS X 10.8 或以上). Windows Phone 程序沒法在OSX上開發; IDE也沒法創建包含Window Phone的項目模板.
Windows 系統要求
Xamarin.Forms 應用程序可以使用Visual Studio 2012(或更新的版本)開發.
- PCL 解決方案模板需要.NET 4.5上的Profile 78 ( Visual Studio 2012 可以安裝Net4.5, Visual Studio 2013已內置). 同時需要安裝Windows Phone SDK ,否則會發生 Project type not supported 的錯誤.
- Shared Project 項目模板需要安裝 Visual Studio 2013 Update 2.
開始使用Xamarin Forms
在開始下面的討論前, 我們需要了解,Xamarin.Forms 其實是以 .NET Portable Class Library (PCL可移植類庫)的形式實現,因為這樣可以在多平台很方便的共享API. 創建應用程序的第一步就是創建解決方案文件
一個Xamarin.Forms 解決方案通常有以下項目組成:
- Portable Library - 這個項目是包含所有共享UI和其他共享的代碼用於跨平台應用程序的類庫.
- Xamarin.Android Application - 這個項目包含Android相關的代碼和一個Android版應用程序的入口點函數.
- Xamarin.iOS Application - 這個項目包含iOS相關的代碼和一個IOS版應用程序的入口點函數.
- Windows Phone Application - 這個項目包含Windows Phone相關的代碼和一個Windows Phone版應用程序的入口點函數.
Xamarin 3.0 提供的解決方案模板,可以創建一個Xamarin Forms程序所必須的所有項目。
在 Xamarin Studio 中, 選File > New > Solution. 在新建解決方案對話框中選C# > Mobile Apps, 然后選擇 Blank App (Xamarin.Forms Portable) .下面是該操作的截圖:

輸入項目名,並按OK按鈕就可以了. 模板會創建一個包含三個項目的解決方案.

使用Xamarin Studio 創建的解決方案不包含 Windows Phone 項目. 使用Visual Studio 新建 Xamarin.Forms 解決方案的話則支持 iOS, Android和 Windows Phone. 需要注意的是雖然 Xamarin Studio不支持創建Windows Phone 應用程序,但是他還是能夠打開一個包含Windows Phone 應用程序項目的解決方案 (如一個被Visual Studio創建的解決方案). 你可以查看 Windows Phone 代碼,但是沒法編譯和部署在Xamarin Studio.
查看一個 Xamarin.Forms 應用程序
默認的模板創建一個最簡單 Xamarin.Forms 應用程序. 如果你運行它,你會看到如下界面:

在上面的截圖中,每個界面都是使用Xamarin Forms的Page 的效果. 一個Xamarin.Forms.Page
在Android中 就是Activity對象 ,在iOS中就是 View Controller對象, 在Windows Phone就是 Page 對象. 上面截圖的HelloXamarinFormsWorld 例子是使用一個Xamarin.Forms.ContentPage
對象,然后展示一個標簽.
為了最大化重用啟動代碼, Xamarin.Forms 應用程序會創建一個叫App的簡單類,作用是實例化第一個展示的Page對象.下面的代碼就是一個App類的例子:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
上述代碼實例化一個ContentPage
對象,該對象會顯示一個單行的 Label,並設置了在頁面中水平和垂直居中
.
在各平台啟動初始化 Xamarin.Forms Page
為了在應用程序中使用Xamarin Forms Page對象, 每個平台上的項目必須初始化 Xamarin.Forms 框架並在啟動時提供一個實例化的ContentPage的對象. 不同平台上的啟動代碼是不一樣的。
Android
在Android中啟動初始化 Xamarin.Forms 頁面, 你必須創建一個使用MainLauncher特性的Activity,就像之前的傳統的Android應用一樣; 除此以外你的activity 還必須繼承至Xamarin.Forms.Platform.Android.AndroidActivity
,然后重寫OnCreate方法,在其中進行 Xamarin.Forms framework的初始化,顯示初始的Page等工作。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
上述代碼會創建一個 Xamarin.Android 應用程序

iOS
在一個 Xamarin.iOS 應用程序中,需要在 AppDelegate 類中初始化 Xamarin.Forms 框架,然后設置RootViewController為初始的Xamarin.Forms Page. 如下面代碼顯示的,這些都要在 FinishedLaunching 方法中完成
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
和andoroid一樣, FinishedLaunching事件的第一步是通過Xamarin.Forms.Forms.Init()初始化
Xamarin.Forms 框架。這樣做原因是因為Xamarin.Forms需要在應用程序中全局加載. 下一步是設置應用程序的根view controller對象. 這需要調用在跨平台類庫中創建的HelloWordPage對象的 CreateViewController()方法。

Windows Phone
在一個 Windows Phone項目中初始頁會初始化Xamarin.Forms框架,然后用 Xamarin.Forms Page對象設置起始頁內容. 下面代碼是如何操作的一個例子:
1
2 3 4 5 6 7 8 9 10 |
|

既然我們已經開始對 Xamarin.Forms有些了解,然后我們開始更詳細討論Xamarin Forms.
Views and Layouts
Xamarin.Forms使用了一個很簡單的API,通過Control對象和Layouts對象組合用於創建UI界面。 在運行時, Xamarin.Forms control會映射到相應的原生控件,並用原生控件來呈現.用於 Xamarin.Forms 應用的界面展示主要是如下4個類:
- View - 在其他平台通常會被稱為controls 或 widgets. 就是相當於標簽,按鈕,文本框等等UI元素.
- Page - 一個Page在應用程序程序代表一個屏幕的內容. 他類似於Android的 Activity, Windows Phone 的Page, iOS 的View Controller.
- Layout - 一種View的子類. 作為放置界面顯示的View對象和其他Layout的容器. Layout 通常包含如何組織呈現子view的邏輯.
- Cell - 這個類是專門的元素用於代表list或table中的項目,它描述了列表中每個元素是如何展示的.
下面是常用的Control:
Xamarin.Forms Control | Description |
Label |
只讀顯示文本 |
Entry |
單行輸入文本框 |
Button |
按鈕 |
Image |
用於展示圖片的控件 |
ListView |
列表清單. |
Controls 本身是由 layout進行布局控制的. Xamarin.Forms 有兩類不同的布局控制方式:
- Managed Layouts - layout負責內部的控件的位置和大小,並且遵循 CSS box model. 應用程序不會直接嘗試去設置控件的大小和位置. 內置的一個Managed Layout的是 the
StackLayout
. - Unmanaged Layouts -和managed layouts相反, unmanaged layouts 不會自動調整屏幕中控件的位置. 通常用戶在加入到layout時要自己指定好位置和大小。內置的
AbsoluteLayout
是一個 unmanaged layout .
讓我們具體討論下 StackLayout
和AbsoluteLayout
.
StackLayout
StackLayout
是最常見的managed layout. StackLayout
可以滿足那些跨平台應用程序開發中希望無視屏幕尺寸,系統自動調整控件位置的需求。每個子元素按照加入layout的順序依次被定位,無論橫向還是豎向 . StackLayout
會使用多少空間,取決於HorizontalOptions
和LayoutOptions
屬性的設置, 默認StackLayout
會使用整個屏幕區域
下列代碼是使用 StackLayout
排列3個Label
控件:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
下列代碼是使用XAML進行同樣的布局:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
下面的截圖我們可以看到默認 StackLayout 會垂直排列

可以通過下面的代碼對 Orientation 和Vertical屬性進行設置
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
下列代碼是使用XAML進行同樣的布局:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
修改后代碼的運行截圖如下

盡管不能顯式地設置StackLayout內控件的大小
, 但是可以通過HeightRequest
和WidthRequest
屬性告訴layout引擎控件具體的大小.
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
下列代碼是使用XAML進行同樣的布局:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
修改后的程序運行結果:

Absolute Layout
AbsoluteLayout
屬於 unmanaged layout. 在layout內的控件必須顯式設置好自己的位置. 這個概念和老早的windows forms和ios平台(沒有使用constarints)上控件定位的方法很像. 由於設置了具體精確的定位位置,我們需要在不同尺寸的屏幕上對layout進行測試來保證效果。
下面是使用 AbsoluteLayout
的簡單例子:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
Conceptually
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
下面的截圖就是最后呈現的結果

需要注意每個被加入Children集合對象的順序影響了
屏幕上元素的Z-order – 第一個加入的在最底下 而隨后加入的控件在他的上面, 會產生覆蓋 (像例子中的綠色標簽).所以絕對布局控件時要注意小心覆蓋導致隱藏其他控件
Xamarin.Forms中的列表
ListViews
在移動應用程序是一個常見控件,所以我們可以詳細討論下. ListView
用於展示一個集合中的項目。在ListVIew中每個項目都是由一個cell組成.默認ListView會使用內置的 TextCell
來輸出一個單行文本。下面的代碼是使用ListView的簡單例子:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
下面是運行的截圖

和一個自定義類綁定
自定義的類也可以使用ListView來綁定顯示. 我們定義以下類:
1
2 3 4 |
|
ListView
可以像下面這樣使用:
1
2 3 4 5 6 7 |
|
為了控制在列表中顯示的內容,需要創建一個binging,並設置綁定的屬性 - 在這個例子中是 Name
屬性.
1
2 |
|
在ListView中選擇一個項目
在ListView中實現ItemSelected
事件可以響應界面上的點擊事件,下面代碼展示顯示一個簡單提示框:
1
2 3 |
|
在一個 NavigationPage中的話,可以使用
Navigation.PushAsync
方法打開一個新的Page進行導航. ItemSelected
事件中可以通過 e.SelectedItem訪問選中的綁定對象
, 我們可以繼續把對象綁定到新的Page然后通過 PushAsync方法展示
:
1
2 3 4 5 |
|
每個平台的導航方式不一樣的.更多內容在 Navigation.
自定義一個Cell的樣式
我們可以通過創建一個ViewCell的子類,並設置到ListView的ItemTemplate屬性上來實現Cell樣式的自定義
看一下下面的截圖樣式

這個cell由一個 Image
控件和兩個Label控件組成
. 為了創建這個自定義的布局,我們需要創建一個 ViewCell
的子類:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
代碼中的內容很多
- 它加入一個
Image控件,然后綁定
ImageUri屬性到
Employee
對象. - 它創建了
StackLayout包含垂直排列的兩個標簽
. 標簽綁定Employee
對象的DisplayName
屬性和Twitter
屬性. - 它創建另一個
StackLayout
用於放置Image
和第二步創建的StackLayout
. 然后使用水平排列.
一旦自定義的 cell類創建好,我們可以使用在ListView中 DataTemplate對象
:
1
2 3 4 5 6 7 |
|
向 ListView傳入一個Empolyee集合對象,每個
cell都會使用EmployeeCell類來呈現
. ListView
會把 Employee
對象通過BindingContext傳入EmployeeCell
使用XAML來自定義一個列表
之前的代碼可以通過如下XAML實現
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
數據綁定
Xamarin.Forms 應用程序使用數據綁定非常方便地顯示和交互數據.它在用戶界面和底層應用程序建立之間的連接. 當用戶編輯文本框的內容時,數據綁定自動更新了所關聯底層對象的屬性 。 BindableObject
包含了很多內容用於實現數據綁定
數據綁定定義了兩個對象間的關系. source 對象提供數據. target對象消費使用來自source數據 (通常是顯示). 例如,一個Label
會顯示Employee
對象.Employee
對象就是 source, Label
就是 target.
如何在 Xamarin.Forms 對象(如 Page 和 Control) 中使用數據綁定,需要遵循下面兩步:
- 設置要綁定對象的 BindingContext 屬性 ,用於綁定的源對象一般都要實現
INotifyPropertyChanged
接口. - Xamarin.Forms 的對象要調用SetBinding 方法進行綁定.
SetBinding
方法有兩個參數. 第一個參數是綁定的類型信息. 第二個參數需要提供綁定什么內容和如何綁定的信息. 一般情況下可以設置為BindingContext中文本型的屬性名, 如果我們直接要綁定, 我們可以這樣寫
1
|
|
點號告訴Xamarin.Forms直接使用 BindingContext
作為數據源,而不是 BindingContext的某個屬性
. 一般在BindingContext
是一個簡單類型,如string或integer.
為了幫助理解如何綁定一個對象到Page上,可以看看下面的截圖

這個 Page使用了以下控件:
Xamarin.Forms.Image
Xamarin.Forms.Label
Xamarin.Forms.Entry
Xamarin.Forms.Button
Page對象通過構造子傳入Employee對象.
1
2 3 4 5 6 7 8 9 10 11 12 |
|
代碼第一行設置了 BindingContext為
一個.NET 對象 –這告訴底層界面需要綁定對象是誰. 下一行實例化了 Xamarin.Forms.Entry
控件. 最后一行綁定 Xamarin.Forms.Entry
和用於顯示的employee對象
; Entry控件Text
屬性被綁定到BindingContext對象的 FirstName
屬性. Entry
控件的變化會自動更新到employeeToDisplay
對象. 同樣, 如果 employeeToDisplay.FirstName的變化也會引起
Entry
控件的顯示.綁定是雙向的.
為了讓雙向綁定起作用, 模型類必須實現 INotifyPropertyChanged
接口.
INotifyPropertyChanged
INotifyPropertyChanged
接口用於當一個對象值發生變化時需要通過客戶端的場景,接口很簡單:
1
2 3 4 5 |
|
INotifyPropertyChanged的對象必須在他的屬性值變化時觸發
PropertyChanged
事件. 下面是一個簡單的例子:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
當某個 MyObject實例的
FirstName
發生變化, OnPropertyChanged
會被調用來觸發PropertyChanged
事件.
注意參數propertyName
使用了 CallMemberName
特性. 當OnPropertyChanged調用時參數為空
, CallMemberName
特性會調用OnPropertyChanged方法的方法名
.
Navigation
現在我們已經明白如何創建一個page並顯示控件,接下來我們討論下如何在page間導航跳轉。. Navigation可以被看做一個后進先出,里面全是Page對象的棧. 在應用程序中從一個page跳到另一個page,只要在棧中壓入一個新的page對象;返回到之前的page則只要在棧中彈出當前的Page。Xamarin.Forms 中的導航使用 INavigation
接口
1
2 3 4 5 6 7 8 |
|
這些方法都返回 Task對象,用於調用代碼確保push和pop page是否成功
Xamarin.Forms 內置了 NavigationPage
對象,實現了上面的接口用於管理page. NavigationPage
類會屏幕上方在加入一個導航工具欄,上面會顯示一個標題,還有與平台相應樣式的返回按鈕用於退回到前一個page。 下面的代碼展示如何在第一個page中使用 NavigationPage
:
1
2 3 4 5 |
|
為了在當前page中顯示LoginPage則需要調用 INavigation.PushAsync
方法
1
|
|
當新的LoginPage 對象被壓入 Navigation 的棧中. 退回前一page, LoginPage 必須調用:
1
|
|
模態的導航也是類似的. :
1
|
|
返回到調用頁的話, LoginPage必須使用:
1
|
|