使用 C# 构建 Android 应用(Xamarin.Forms 入门)






4.83/5 (18投票s)
使用 Xamarin Forms 构建 Android 应用的基础知识
什么是 Xamarin?
我们不能直接创建一个 Android 项目然后开始用 C# 编写代码。那样太疯狂了!对吧?我们需要某种包装器或框架。您可能听说过一个名为 Cordova 的 JavaScript 框架,它允许您使用 Web 技术栈(HTML、CSS、JavaScript)编写跨平台移动应用。同样,现在我们也可以使用 Xamarin 框架用 C# 编写跨平台应用。Xamarin 提供了三种解决方案模板来构建移动应用
Xamarin.iOS
(仅用于创建 iOS 应用。使用 Storyboard 设计 UI 并将其连接到您的 C# 后端代码,而不是 Objective C 或 Swift)Xamarin.Android
(仅用于创建 Android 应用。使用 AXML 设计 UI,而您将使用 C# 作为后端代码,而不是 Java)Xamarin.Forms
(用于创建 iOS、Android 和 Windows 应用。该框架提供了一组 UI 组件,用于创建可以在多个平台之间共享的布局。使用 XAML 进行 UI 设计,并使用 C# 作为后端代码。)
为什么选择 Xamarin.Forms?
我将在演示中使用 Xamarin.Forms
,我很快就会展示。选择 Xamarin.Forms
的原因是我是一名 Windows Phone 开发者(罪无可恕),这意味着我already 知道 XAML。此外,我非常喜欢代码共享,这意味着我喜欢编写一次代码,然后在所有可能的平台上运行它。如果您想了解更多关于 Xamarin 的信息,可以点击这里访问他们的官方网站。
我们要构建什么?
Xamarin.Forms
是构建数据驱动应用的绝佳选择。所以,让我们来做一个吧。让我们创建一个应用,它将在 ListView
中显示《星球大战》电影中的所有角色。我在网上找到了一个免费的 API(https://swapi.co/),我可以在其中以 JSON 格式获取所有电影角色,从这里获取。
构建应用程序
打开 Xamarin Studio。创建一个新的 Xamarin.Forms
应用。给您的应用命名。您可以保留标识符不变。如果您在 MAC 上,iOS 复选框将为您启用。由于我在 Windows 上,所以我只能定位 Android 平台。在共享代码部分选择便携式或共享类库。完成后续步骤。
创建解决方案后,您将在解决方案中看到三个项目。一个是共享代码(starwars),一个是 Android 应用,最后一个正如其名,是一个用于您应用的 UI 测试项目。只需将 starwars.Droid
设置为启动项目并运行您的应用。
在将应用的各个部分连接起来之前,让我们讨论一下这个骨架应用的一些基本知识。那么“欢迎来到 Xamarin Forms!”是从哪里来的呢?如果您转到 startwars.cs 文件,您将看到这个魔法的确切原因!在 App()
构造函数中,我们将 MainPage
(起始页)属性设置为新实例化的 ContentPage
。这是 Xamarin 为我们提供的用于构建应用 UI 的众多内置类之一。ContentPage
中的其他所有内容都是不言自明的。我们向 Content
属性添加了一个 StackLayout
。StackLayout
用于将控件堆叠在 ContentPage
上。StackLayout
本身在页面上垂直居中(VerticalOptions = LayoutOptions.Center
)。我们有一个 Label
,用于在 StackLayout
的子项中显示纯文本。文本在 Label
的中心对齐(XAlign = TextAlignment.Center
)。我已经将所有代码映射到输出布局,以便您对正在发生的事情有一个很好的理解。
我们可以向项目中添加一个独立的 ContentPage
,并使用 XAML 模仿所有这些内容。所以,右键单击并向共享项目添加一个新文件。从列表中选择“Forms ContentPage Xaml”。由于我将在这里展示所有《星球大战》角色,所以我将其命名为 SWCharacters
。
添加后,我们将有一个 XAML 文档,其中包含一个连接的 C# 后端代码。
如果您仔细观察,您会发现我们已经设置了 ContentPage
和 Content
节点。现在是时候添加我们缺少的内容了。
如您所见,我已经为视图添加了等效的 XAML 标记。现在,我们可以删除附加到 MainPage
属性的所有代码,并附加一个新创建的 ContentPage
的新实例。保存所有内容,然后运行您的应用。您将获得与之前相同的结果。
基础知识够了。让我们回到我们的应用。我们需要对 API(https://swapi.co/people)进行 HTTP 调用以获取所有角色。为此,我们需要添加 Microsoft HTTP Client Libraries package
。我们还需要 Json.NET
,它将帮助我们解析原始 JSON 数据到类对象。从 Nuget 搜索并将两者都添加到您的项目中(选择共享项目 > 从顶部菜单栏的“项目”菜单中选择 > 添加 Nuget 程序包)。
转到 SWCharacters
后端代码(SWCharacters.cs)并添加下面提供的代码行
public ObservableCollection<people> Peoples { get; set; }
private HttpClient _client;
private const string PeopleDataUrl = "http://swapi.co/api/people";
public SWCharacters ()
{
InitializeComponent ();
Peoples = new ObservableCollection<people>();
}
public async Task GetAllCharacters()
{
try
{
_client = new HttpClient();
var response = await _client.GetStringAsync(PeopleDataUrl);
if (!string.IsNullOrEmpty(response))
{
var data = JsonConvert.DeserializeObject<rootobject>(response);
foreach (var people in data.Peoples)
{
Peoples.Add(people);
}
}
}
catch (Exception)
{
await DisplayAlert("Error", "Something went wrong", "Ok");
}
}
private async void PeopleButton_OnClicked(object sender, EventArgs e)
{
GetAllCharacters();
}
我通过对 https://swapi.co/people 进行 HTTP 'GET
' 调用,并将结果序列化为 People
对象的 ObservableCollection
(C# 中 List
类的扩展版本),使用了 Json.Net 的 JsonConvert.DeserializeObject
。要了解更多关于序列化的信息,您可以阅读我在这里的这篇博文 - http://fiyazhasan.me/serialization-for-fun/。这是我之前提到的序列化对象类。属性([JsonObject("Result")]
、[JsonProperty("results")]
)仅用于给这些类和属性起一个通用的名称。
People.cs
[JsonObject("Result")]
public class People
{
public string name { get; set; }
public string height { get; set; }
public string mass { get; set; }
public string hair_color { get; set; }
public string skin_color { get; set; }
public string eye_color { get; set; }
public string birth_year { get; set; }
public string gender { get; set; }
public string homeworld { get; set; }
public string created { get; set; }
public string edited { get; set; }
public string url { get; set; }
}
public class RootObject
{
public int count { get; set; }
public string next { get; set; }
public object previous { get; set; }
[JsonProperty("results")]
public List<people> Peoples { get; set; }
}
现在,您可以问我从哪里得到这个类。生成用于序列化的类对象非常容易。我去了 https://swapi.co/ 并向其 https://swapi.co/people API 发起了一个请求。我复制了 JSON 结果。然后我去了这个网站 - http://json2csharp.com/ 并粘贴了我的 JSON 以获取相应的类对象。请看下面的图片
我在项目中创建了一个类文件,并将这两个类粘贴到其中。我在这里完成了。您可以在 SWCharacters.cs 中看到一个 PeopleButton_OnClicked
事件。那是因为我希望只在从 UI 点击该按钮时才启动 HTTP 调用。这是为应用创建按钮的新 XAML 标记。
<ContentPage.Content>
<StackLayout VerticalOptions="Center">
<Button x:Name="PeopleButton"
Text="Get People" Clicked="PeopleButton_OnClicked"></Button>
</StackLayout>
</ContentPage.Content>
现在,如果您运行该项目并单击按钮,您将从 API 中获取人员数据。该按钮仅用于检查我们是否成功调用了 API。我设置了一些调试点并检查一切是否正常。
接下来,我们将用 ListView
控件替换按钮,并将其 ItemSource
属性绑定到我们的人员 ObservableCollection
。用以下内容替换您之前的 XAML 标记
<ContentPage.Content HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<StackLayout>
<ListView x:Name="PeopleListView" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid Padding="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Label Text="{Binding name}"
FontSize="16" Grid.Row="0"></Label>
<Label Text="{Binding height}"
Grid.Row="1"></Label>
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
所以,我们有一个 ListView
而不是之前那个按钮。要设置添加到 ListView
的项的外观和感觉,我们有 ListView.ItemTemplate
。要能够将 ListView.ItemTemplate
内的控件绑定到相应列表项的属性,我们有 DataTemplate
。ViewCell
是 Xamarin 提供的众多 Cell 控件之一。ViewCell
仅用于显示原始数据,如果您想将 textbox
控件作为列表项的一部分,可以使用 EntryCell
。我在 ViewCell.View
中放置了另一个 Grid
布局,最后添加了两个 Labels
。一个 Label
绑定到字符的 name
属性,第二个 Label
绑定到 height
属性。新的后端代码如下所示
public partial class SWCharacters : ContentPage
{
public ObservableCollection<people> Peoples { get; set; }
private HttpClient _client;
private const string PeopleDataUrl = "http://swapi.co/api/people";
public SWCharacters ()
{
InitializeComponent ();
Peoples = new ObservableCollection<people>();
GetAllCharacters();
}
public async Task GetAllCharacters()
{
try
{
_client = new HttpClient();
var response = await _client.GetStringAsync(PeopleDataUrl);
if (!string.IsNullOrEmpty(response))
{
var data = JsonConvert.DeserializeObject<rootobject>(response);
foreach (var people in data.Peoples)
{
Peoples.Add(people);
}
PeopleListView.ItemsSource = Peoples;
}
}
catch (Exception)
{
DisplayAlert("Error", "Something went wrong", "Ok");
}
}
}
由于我已从视图中删除了按钮,因此我还删除了与之关联的事件处理程序,并在主构造函数中启动了 HTTP 请求。同样,我将我们的 ListView
的 ItemSource
属性绑定到我刚才提到的可观察集合(PeopleListView.ItemsSource = Peoples;
)。现在,如果您运行此项目,过一会儿,您将看到字符列表,其中 name
和 height
属性显示在相应的标签上。
您应该关心什么?
为了使此演示项目简单易懂,我做了一些违反规则的事情。例如,我从构造函数中调用了一个异步过程。这绝对不好!您可以在网上搜索并遵循编写异步代码的最佳实践。同样,我在 XAML 后端代码中编写了大量代码。基本上,在现实生活中,您会遵循 MVVM 等模式,这将从 UI 后端中删除这些代码,并使您的应用可进行单元测试。
下载并运行应用
将解决方案下载为 zip 格式。解压缩并在 Xamarin Studio 中打开它。我已从项目中删除了所有程序集 .dll 文件。所以您需要恢复程序包。就像您在项目中添加 nuget 程序包一样,从它下面的选项中恢复程序包。
下一步?
以上就是使用 Xamarin Forms 构建应用的一些基础知识。可以将此视为一个“Hello World
”程序。下载项目并添加更多功能,例如为特定角色创建详细信息页面,添加加载指示器以使用户知道您正在从互联网下载内容。再次玩转 https://swapi.co/ 上提供的 API,创建一个完整的《星球大战》粉丝应用。您可以在此处找到大量可供您使用的控件 - https://developer.xamarin.com/guides/cross-platform/xamarin-forms/controls/。如果遇到任何问题,请遵循 Xamarin 的 API 文档。玩得开心,下篇文章再见,各位极客!