这一系列是翻译的微软官方出的有关Xamarin的文档(Creating
Mobile Apps with Xamarin.Forms),由于Xamarin现在还属于一个新型事物,中文文档非常稀缺,这给英文能力有限的开发者造成了一定的阻碍,所以特此翻译。由于本人翻译水平有限,如有任何不正确或不恰当的地方,欢迎指正。我们的翻译从本书的第二章开始(第一章讲解Xamarin的好处的以及搭建环境等,就不翻译了,如果有人提出需求再翻译),后续的翻译将会严格按照书中的章节对应,并会在附件中附上书中所有谈到的例子的源码,希望能够帮助到大家。
由于工作原因,博客更新的可能会比较慢,敬请见谅。
一个现代的用户接口通常是由各种各样的可视对象构成的。在不同的操作系统中,这些可视对象有着不同的名称,如:controls, elements, views, widgets— 但是他们的作用都是展示和交互。
上述的这些概念并不是抽象抽象的。Xamarin.Forms的API(application programming interface)定义了一些名叫VisualElement, Page, Layout, and View的类。这些类以及他们的后代成为了Xamarin.Forms用户界面的中坚力量。VisualElement可以是任何占用屏幕空间的元素。
一个Xamarin.Forms的应用通常由一个或多个页面(page)组成,一个页面通常占用了整个屏幕的控件(或者屏幕的大部分控件)。有些应用甚至只有一个页面,但有的应用有多个页面,每个页面上可能有一个标题。在后面的几篇文章里,你将会看到一种page,名叫ContentPage。为了方便,我们在讲解其他内容时通常都用这一种页面。
每个页面的可是元素都呈现出一种亲子层级关系。ContentPage 的孩子通常是以某种布局(layout)来显示的。有些布局(layout)只有一个孩子,但更多的布局是在自身中包含了多个孩子的。这些孩子既可以是别的布局(layout)也可以是一个视图(view)。不同类型的布局(layout)包含孩子的方式是不一样的,有堆叠式的排布,或者一个两列的网格的排布,或者其他更自由的方式。这一讲我们只讲包含单一孩子的情况。
Xamarin.Forms的View是只指一些展示性的或者交互性的对象,例如: text, bitmaps, buttons, text-entry fields, sliders, switches, progress bars, date 和 time pickers, 或者其他的自定义的控件。他们通常在编程环境里被称为controls或者widgets ,但是我们这里把它称作view 或者 elements。
我们现在用标准模板创建一个新的Xamarin.Forms 应用。Windows系统使用Visual studio , mac 系统使用Xamarin Studio。
【Visual Studio】打开Visual Studio ,选择菜单栏的File > New > Project.这时会弹出来一个窗口,选择窗口左侧的 Visual C# 的Cross-Platform。你会看见在窗口的中间部分提供了一些solution模板,其中包括以下三个:
我们非常确定我们是想建立一个blank app,但是究竟应该选择那一种呢?
【Xamarin Studio】Xamarin Studio 的情况和Visual Studio非常的类似,但是方式有些不一样。打开Xamarin Studio,选择菜单栏上的File > New > Solution。这时候也会弹出来一个窗口,在窗口的左边我们选择Forms App,点击下一步。这时候我们会看到两个选项:
这里的‘便携式’(Portable)指的是可移植类库(PCL)。所有的常见应用的代码都会变成受独立平台引用的动态链接库(DLL)。
这里的‘共享’(Shared)指的是包含一些松散的代码的共享资产项目(SAP),这些松散的代码分散在每一个平台。(这里感觉翻译的不好,把原文留在这里,求指正The term “Shared” in this context means a Shared Asset Project (SAP) containing loose code files (and perhaps other files) that are shared among the platform projects, essentially becoming part of each platform project.)。
在这里,我们选择第一个:
在Visual Studio里的Blank App (Xamarin.Forms Portable) ,在Xamarin Studio里面选择Use Portable Class Library 。
我们可以给新建的这个项目明一个名称,比如”Hello“,并且选择他存储的位置。
如果你是在 Visual Studio 上运行,你会发现在一个名称为Hello的solution下面,我们创建了6个工程:一个普通的工程(PCL工程)和5个应用程序。具体如下:
如果你是在Mac上的Xamarin Studio上运行,则不会创建Windows程序或者Windows Phone程序。
当你创建了一个Xamarin.Forms solution时,他会自动的从NuGet package manager 里导入所需的Xamarin.Forms libraries(以及一些其他的各式各样的libraries)。Visual Studio 和 Xamarin Studio都把这些libraries存在一个名叫packages的目录下,这个目录位于solution中。当然,solution模板会指定一个特定版本的Xamarin.Forms library,如果有新版本,他也会提示可更新。
在Visual Studio里,屏幕右侧有一个Solution Explorer,右键你的solution的名称,选择Manage NuGet Packages。这时会弹出一个对话框,对话框里你可以看到当前的版本以及可选的版本。当然,你也可以选择Update去更新你的Xamarin.Forms library.
在Xamarin.Studio中,你可以点击你的solution 名称右边的工具图标并选择Update NuGet Packages.
在进行下一步之前,我们先来检查下我们的配置是不是都是正常的:
在Visual Studio中,选择菜单栏上的 Build > Configuration Manager ,会弹出一个配置对话框,你会看到一个PCL程序和5个应用程序。首先确定所有的应用程序都的build和Deploy复选框都被勾选上(灰色的复选框除外)。然后再看一下平台组(Platform column)的情况:
列表中的Hello程序以及Hello,Droid应该被标记为: Any CPU。(对于这两个程序来说这是唯一选项);
对于 Hello.iOS 程序,你可以选择一个iPhone 或者 iPhoneSimulator ;
对于 Hello.UWP 程序, 如果是运行在桌面或者是模拟器中,请选择 x86 ,如果是运行在手机上,请选择ARM;
对于 Hello.WinPhone 程序, 如果你要使用模拟器,请选择 x86 ,如果你是使用真机调试,请选择 ARM 或者 Any CPU. 无论您选择的哪一种,Visual Studio都会生成相同的代码。
如果程序并没有正常的编译或者部署的话,再次检查Configuration Manager窗口的配置是否正确。有些配置被激活后,可能不包含在 PCL程序里。
在Mac系统的Xamarin Studio中,你可以在Project > Active Configuration 中选择iPhone或者iPhone模拟器。
在Visual Studio中,你可以选择显示iOS和Android的工具栏(toolbars)。勾选上View > Toolbars > iOS 或者 View > Toolbars > Android,可以使得这些工具栏可以在模拟器或者真机中显示。
因为这个solution包含了不同平台的程序,你需要选择将其中一个选为默认的程序,这可以方便你之后运行或者调试你的程序。在 Visual Studio中,你可以选择右键任意一个程序并且点击Set As StartUp Project ,之后你可以选择一个模拟器或者真机,选择完毕之后每次只要点击Debug > Start Debugging 就可以快速的编译并运行你的代码了。
同样的,你在Xamarin Studio中也可以做同样的事。点击相应程序的小工具图标,在弹出的窗口中选择Set As Startup Project,之后也同样可以通过点击 Run > Start Debugging编译并运行你的代码。
你可以看到,不同的平台有不一样的样式。iOS和windows 10 手机的都是深色的字和浅色的底色,而Android手机则是浅色的文字和深色的底色。默认情况下Windows 8.1 和 Windows Phone 8.1平台上的样式和Android类似。
这些平台默认就支持横屏,你可以把屏幕横过来,你会看到文字依然会在整个屏幕的中间。
这些app是部署并运行在各自的平台上的,你可以像使用其他应用一样使用它。如果你不喜欢这个应用的图标或者是应用名称的显示方式,你可以在各个不同平台上更改他们。
很明显,这个用 Xamarin.Forms的模板创建出来的应用程序是非常简单的,所以我们可以趁这个机会来研究一下他自动生成的代码,找出他们之前的联系,明白他们究竟是怎样工作的。
我们先从在屏幕上显示文字的代码开始。Visual Studio中有一个名叫App.cs的文件, Xamarin Studio中有一个名叫Hello.cs的文件。这里面有一个名叫App Class的类。如果程序模板和我写这一章节的时候的模板没有变化太大的话,他看起来可能是类似于这样的:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Hello
{
public class App : Application
{
public App()
{
// The root page of your application
MainPage = new ContentPage
{
Content = new StackLayout
{
VerticalOptions = LayoutOptions.Center,
Children = {
new Label {
HorizontalTextAlignment = TextAlignment.Center,
Text = "Welcome to Xamarin Forms!"
}
}
}
};
}
protected override void OnStart()
{
// Handle when your app starts
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
}
}
我们可以看到,namespace和工程的名称是一致的。App class 是一个public的类,他继承于Xamarin.Forms Application 类。他的构造函数有且只有一个作用:to set the MainPage property of the Application class to an object of type Page.
Xamarin.Forms的模板在这里生成的代码显示出了一种非常简单的方法来定义这个构造函数:ContentPage 类继承于Page类,它是一种非常常用的页面,尤其是在单页面的Xamarin.Forms应用程序中。(你将在之后看到我们大量的使用这种页面)这种页面会占有安卓手机除去状态栏和底下的虚拟键盘栏之外的整个屏幕,对于windows phone也是如此,他会占有除了状态栏之外的所有空间。(但是如果你仔细看的话你会发现,在iOS手机上,状态栏变成了整个ContentPage的一部分)
ContentPage类定义了一个叫做Content的属性,在这个属性里,你可以定义一个页面的内容。通常情况下,content内一般放置一个包含了一系列视图(view)的布局(layout)。在上面这个例子里面使用的布局名叫StackLayout,StackLayout是一个常用的布局,顾名思义,他让里面的孩子(view 或者 layout)按一定顺序堆叠在里面。
这个栗子中,StackLayout只有一个孩子:Label。Label类继承于View,在Xamarin.Forms应用程序中用于显示一段文字。VerticalOptions 和 HorizontalTextAlignment 是他的属性,这个我们将会在稍后讲到。
对于你自己的但页面的Xamarin.Forms应用程序,你通常会让你自己的类继承于ContentPage。在App的构造函数中,你实例化了一个Content Page类,并把它赋值给MainPage属性。稍后我们将讲解他具体是怎样工作的。
在Hello这个解决方案(Hello solution)中,你会看到一个名叫AssemblyInfo.cs的文件, 这个文件是用来创造PCL和包含了工程要求的NuGet packages的packages.config文件的。在Hello的解决方案下有一个名叫References的文件夹,里面列出了一些PCL要求的包。这些包至少包含下面四种:
当你在编写Xamarin.Forms应用时,你需要将大部分的注意力都集中在PCL工程上。在部分情况下,不同的平台可能要求不同的样式,对于这种情况我们一会儿就来讲解。你还可以在五个应用中引用特定平台的代码。
这五个不同的应用程序都有他们自己的财产(assets)包括图标和元数据。如果你的应用要推向市场,你可能需要注意一下这些财产(assets)。如果你只是学习如何用Xamarin.Forms开发应用,你可以暂且忽略他们。你可以先暂时折叠他们,避免他们干扰。
现在我们还是再来简单的了解下他们。
在每一个应用程序项目的参考部分,你会看到常见的PCL项目(在上例中是hello)引用,以及各种.NET程序集,该Xamarin.Forms组装上面列出的和额外的Xamarin.Forms组件适用于每个平台:
上面这些库每一个都定义了一个静态方法,叫做Forms.Init。这个方法在Xamarin.Forms命名空间里为特定的平台初始化了Xamarin.Forms系统。每个平台的起始代码都必须要调用这个方法。
你可以看到,PCL工程里面派生了一个公用的类,名叫App,这个类派生于Application。任何平台的起始代码都需要实现这个App类。
如果你是一个熟悉 iOS, Android,或者 Windows Phone 的开发者,你可能会很好奇各个平台其实代码是怎样工作的。
iOS工程的特点是包含了一个派生于UIApplicationDelegate的类。Xamarin.Forms.Platform.iOS包定义了一个可替代的基类,名叫FormsApplicationDelegate。在Hello.iOS工程中,你会看到一个名叫AppDelegate.cs的文件,这里去掉了所有的多余的using指令以及注释:
using Foundation;
using UIKit;
namespace Hello.iOS
{
[Register("AppDelegate")]
public partial class AppDelegate:
global::Xamairn.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
return base.FinishedLaunching
}
}
重写的FinishedLaunching以调用定义在Xamarin.Forms.Platform.iOS的集合(assembly)中的Forms.Init方法开始。紧接着调用在FormsApplicationDelegate中定义的LoadApplication方法,参数是在PCL工程中定义在Hello命名空间下的App类的一个实例。page对象被赋给了App对象的MainPage属性,这可以用来创建一个类型为UIViewController的对象,他的职责主要是渲染页面的内容。
在Android应用中,最典型的MainActivity类要派生于 Xamarin.Forms类的FormsApplicationActivity,他被定义于Xamarin.Forms.Platform.Android 集合中,Forms.Init 调用请求一些额外的信息:
using Android.App;
using Android.Content.PM;
using Android.OS;
namespace Hello.Droid
{
[Activity(Label = "Hello", Icon = "@drawable/icon", MainLauncher = true,ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
}
}
定义于FormsApplicationActivity的LoadApplication方法传递了一个参数:在Hello命名空间中的App类的一个实例。MainActivity的的属性表明了当屏幕更改横竖方向(从横屏转成竖屏或者反过来)以及屏幕大小改变时,activity不会重新创建。
在UWP工程(或者其他两个Windows工程)里,我们首先来看看夹在App.xaml文件下的App.xaml.cs文件。在OnLaunched方法中,你会看到他调用Forms.Init时传递了事件参数:
Xamarin.Forms.Forms.Init(e);
紧接着我们来看一下夹在MainPage.xaml文件下的MainPage.xaml.cs文件。这个文件定义了常见的MainPage类,但事实上他派生于MainPage.xaml文件中根元素指定的Xamarin.Forms类。定义在这个基类的LoadApplication方法传递了一个新的App类的实例:
namespace Hello.UWP
{
public sealed partial class MainPage
{
public MainPage()
{
this.InitializeComponent();
LoadApplication(new Hello.App());
}
}
}
如果你已经创建的Visual Studio下的Xamarin.Forms解决方案,并且不希望针对一个或多个平台,只需删除这些项目就可以了。
如果你改变了注意想重新添加回删除的工程,或者你已经在Xamarin Studio上创建了一个解决方案,但为了Windows平台想要挪到Visual Studio上去,你可以添加新的平台工程。在 Add New Project窗口你可以选择iOS的Universal类型以及Blank App 模板创建一个统一API的Xamarin.iOS工程,也可以用Android Blank App模板创建一个Xamarin.Android工程,或者在Windows标题(UWP工程)下选择Universal,或者在Windows 8标题下选择Windows或者Windows Phone,并用Blank App创建一个工程。
对于这些新的工程,你可以通过咨询由标准Xamarin.Forms模板生成的项目获得正确的引用。
总结一下:Xamarin.Forms的应用除了Xamarin.Forms包不同外,其他和普通的Xamarin或者Windows Phone工程比,真是没什么特别的。ㄟ( ▔ , ▔ )ㄏ
下一节我们将简单的介绍SAP和PCL的区别,并介绍下显示文字的视图:Label。