向 .NET MAUI 应用添加可视控件
现在你已使用 .NET MAUI 模板创建了应用程序,下一步是添加用户界面并实现初始 UI 逻辑。
在本单元中,你将详细了解 .NET MAUI 应用程序的构建基块和导航结构。
.NET MAUI 项目中有何内容?
总的来说,.NET MAUI 项目最初包含:
-
MauiProgram.cs 文件,其中包含用于创建和配置应用程序对象的代码。
-
App.xaml 和 App.xaml.cs 文件,用于提供 UI 资源并为应用程序创建初始窗口。
-
AppShell.xaml 和 AppShell.xaml.cs 文件,用于指定应用程序的初始页面并处理导航路由的页面注册。
-
MainPage.xaml 和 MainPage.xaml.cs 文件,用于定义初始窗口中默认显示的页面的布局和 UI 逻辑。
可根据需要向应用添加更多页面,并可创建更多类来实现应用所需的业务逻辑。
.NET MAUI 项目还包含一组默认的应用程序资源(例如图像、图标和字体)以及每个平台的默认启动代码。
应用程序类
App
类将 .NET MAUI 应用程序作为一个整体来表示。 它从 Microsoft.Maui.Controls.Application
继承一组默认行为。 回顾上一单元,App
类是启动代码为每个平台实例化和加载的。 反过来,App
类构造函数通常会创建 AppShell
类的实例并将其分配给 MainPage
属性。 正是此代码控制用户通过 AppShell
中定义的内容看到的第一个屏幕。
App 类还包含以下内容:
-
处理生命周期事件的方法,包括将应用发送到后台时(即当应用不再是前台应用时)。
-
为应用程序创建新
Windows
的方法。 .NET MAUI 应用程序默认只有一个窗口,但你可以创建并启动更多窗口,这对于桌面应用程序和平板电脑应用程序很有帮助。
Shell
.NET Multi-platform App UI (.NET MAUI) Shell 通过提供大多数应用需要的基本功能来降低应用开发的复杂性,包括:
- 用于描述应用的视觉层次结构的单个位置。
- 常见的导航用户体验。
- 支持导航到应用中任何页面的基于 URI 的导航方案。
- 集成的搜索处理程序。
在 .NET MAUI Shell 应用中,应用的视觉层次结构是在 Shell 类的子类中描述的。 此类可以包含三个主要的层次结构对象:
FlyoutItem
或TabBar
。FlyoutItem
表示浮出控件中的一个或多个项,应在应用的导航模式需要浮出控件时使用。TabBar
表示底部选项卡栏,应在应用的导航模式以底部选项卡开始且不需要浮出控件时使用。Tab
,表示分组内容,可通过底部选项卡导航。ShellContent
,表示每个选项卡的 ContentPage 对象。
这些对象不表示任何用户界面,而是表示应用的视觉层次结构的组织。 Shell 会接收这些对象并为内容生成导航用户界面。
页
页是 Shell
中 .NET MAUI 中的 UI 层次结构的根。 目前你所见到的解决方案包括一个名为 MainPage
的类。 此类派生自 ContentPage
,这是最简单和最常见的页类型。 内容页仅显示其内容。 .NET MAUI 还具有几种其他内置页类型,包括以下类型:
-
TabbedPage
:这是用于选项卡导航的根页。 选项卡式页包含子页对象;每个选项卡各一个。 -
FlyoutPage
:通过此页可实现大纲/细节样式呈现。 浮出控件页包含一系列项。 选择某一项时,将会出现显示该项详细信息的视图。
其他页类型也可用,主要用于在多屏幕应用中启用不同的导航模式。
视图
内容页通常显示一个视图。 视图支持以特定方式检索和显示数据。 内容页的默认视图是 ContentView
,它按原样显示各项。 如果缩小视图,项可能会从界面中消失,直到重设视图大小。 ScrollView
支持使用滚动窗口显示项;如果你缩小窗口,可以上下滚动以显示各项。 CarouselView
是一个可滚动视图,使用户能够浏览项集合。 CollectionView
可以从命名数据源检索数据,并以模板为格式呈现每个项。 还有许多其他类型的视图可用。
控件和布局
视图可以包含单个控件,例如按钮、标签或文本框。 (严格来说,视图本身是一个控件,因此一个视图可以包含另一个视图)。但是,限制为单个控件的用户界面不太有用,因此控件被放置在布局中。 布局可定义这些控件相对于彼此显示的规则。 布局也是一个控件,因此可将其添加到视图中。 如果查看默认 MainPage.xaml 文件,你会看到此页面/视图/布局/控件层次结构正在运行。 在这段 XAML 代码中,VerticalStackLayout
元素只是另一个让你能够微调其他控件的布局的控件。
<ContentPage ...>
<ScrollView ...>
<VerticalStackLayout>
<Image ... />
<Label ... />
<Label ... />
<Button ... />
</VerticalStackLayout>
</ScrollView>
</ContentPage>
用于定义布局的一些常见控件包括:
-
VerticalStackLayout
和HorizontalStackLayout
,它们是经过优化的堆积布局,可在从上到下或从左到右的堆栈中布置控件。StackLayout
也可用,它有一个名为StackOrientation
的属性,可将其设置为Horizontal
或Vertical
。 在平板电脑或手机上,在应用程序代码中修改此属性可在用户旋转设备时调整显示内容: -
AbsoluteLayout
,支持设置控件的确切坐标。 -
FlexLayout
,它类似于StackLayout
,不同之处在于它允许包装其包含的不适合单行或单列的子控件。 此布局还提供了用于对齐和适应不同屏幕大小的选项。 例如,垂直排列时,FlexLayout
控件可以使其子控件左对齐、右对齐或居中对齐。 水平对齐时,可以使控件两端对齐以确保均匀的间距。 可使用ScrollView
中的水平FlexLayout
显示一系列可水平滚动的框架(每个框架本身可以是垂直排列的FlexLayout
): -
Grid
,根据我们设置的列和行位置来布置其控件。 你可以定义列和行的大小以及范围,因此网格布局不一定具有“棋盘外观”。
下图汇总了这些常见布局类型的关键特性:
堆积布局显示了垂直排列的四个框。 绝对布局显示了在屏幕上排列的四个框,完全按照开发人员指定的位置排列。 Flex 布局显示了在屏幕上布局的多个框,充分利用了屏幕区域。 网格布局显示了屏幕上以网格模式布局的多个框。
所有控件都有属性。 可使用 XAML 为这些属性设置初始值。 在许多情况下,可在应用程序的 C# 代码中修改这些属性。 例如,处理默认 .NET MAUI 应用中的“单击我”按钮的 Clicked
事件的代码如下所示:
int count = 0; private void OnCounterClicked(object sender, EventArgs e) { count+=5; if (count == 1) CounterBtn.Text = $"Clicked {count} time"; else CounterBtn.Text = $"Clicked {count} times"; SemanticScreenReader.Announce(CounterBtn.Text); }
此代码修改页中 CounterBtn 控件的 Text
属性。 你甚至可以在代码中创建整个页面、视图和布局;无需使用 XAML。 例如,考虑页的以下 XAML 定义:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Phoneword.MainPage"> <ScrollView> <VerticalStackLayout> <Label Text="Current count: 0" Grid.Row="0" FontSize="18" FontAttributes="Bold" x:Name="CounterLabel" HorizontalOptions="Center" /> <Button Text="Click me" Grid.Row="1" Clicked="OnCounterClicked" HorizontalOptions="Center" /> </VerticalStackLayout> </ScrollView> </ContentPage>
等效的 C# 代码如下所示:
public partial class TestPage : ContentPage { int count = 0; // Named Label - declared as a member of the class Label counterLabel; public TestPage() { var myScrollView = new ScrollView(); var myStackLayout = new VerticalStackLayout(); myScrollView.Content = myStackLayout; counterLabel = new Label { Text = "Current count: 0", FontSize = 18, FontAttributes = FontAttributes.Bold, HorizontalOptions = LayoutOptions.Center }; myStackLayout.Children.Add(counterLabel); var myButton = new Button { Text = "Click me", HorizontalOptions = LayoutOptions.Center }; myStackLayout.Children.Add(myButton); myButton.Clicked += OnCounterClicked; this.Content = myScrollView; } private void OnCounterClicked(object sender, EventArgs e) { count++; counterLabel.Text = $"Current count: {count}"; SemanticScreenReader.Announce(counterLabel.Text); } }
C# 代码更详细,但是更加灵活,让你能够动态地调整 UI。
要在应用程序开始运行时显示此页,请将 AppShell
中的 TestPage
类设置为主 ShellContent
:
<ShellContent Title="Home" ContentTemplate="{DataTemplate local:TestPage}" Route="TestPage" />
优化布局
在控件周围添加一点喘息空间非常有用。 每个控件都有一个布局遵循的 Margin
属性。 可以将边距视为控件之间的一种间隔。
所有布局还有 Padding
属性,可以防止其子级靠近布局的边框。 理解此概念的一种方式是,所有控件都在一个盒子中,而这个盒子的墙壁上有垫子。
另一个有用的空白设置是 VerticalStackLayout
或 HorizontalStackLayout
的 Spacing
属性。 这是布局的所有子级之间的空间。 这可与控件自身的边距相加,因此实际的空白将是边距加间距。