自定义基于XAML的视图
上一章中的ScaryColorList程序使用Frame,BoxView和Label在StackLayout中列出了一些颜色。即使只有三种颜色,重复标记也开始变得非常不祥。遗憾的是,没有XAML标记复制C#for和while循环,因此您可以选择使用代码生成多个类似的项目,或者在标记中找到更好的方法。
在本书中,您将看到几种在XAML中列出颜色的方法,最终,一种非常干净和优雅的方式来完成这项工作将变得清晰。但这需要更多的步骤来学习Xamarin.Forms。在此之前,我们将研究一些您可能会在类似情况下发现有用的其他方法。
一种策略是创建一个自定义视图,其唯一目的是显示带有名称和彩色框的颜色。当我们在它的时候,让我们也显示颜色的十六进制RGB值。然后,您可以在XAML页面文件中将该自定义视图用于各个颜色。
在XAML中,对这样的自定义视图的引用可能是什么样的?
或者更好的问题是:你想看它怎么样?
如果标记看起来像这样,那么重复一点也不差,并且比在代码中明确定义Color值数组更糟糕:
<StackLayout>
<MyColorView Color="Red" />
<MyColorView Color="Green" />
<MyColorView Color="Blue" />
</StackLayout>
嗯,实际上,它看起来不会那样。 MyColorView显然是一个自定义类,不是Xamarin.Forms API的一部分。 因此,如果没有XML名称空间声明中定义的名称空间前缀,它就不会出现在XAML文件中。
应用此XML前缀后,对于此自定义视图是Xamarin.Forms API的一部分不会有任何混淆,所以让我们给它一个更加尊严的ColorView名称而不是MyColorView。
这个假设的ColorView类是一个相当简单的自定义视图的示例,因为它仅包含使用StackLayout以特定方式排列的现有视图(特别是Label,Frame和BoxView)。 Xamarin.Forms定义了一个专门用于为这种视图排列提供父母的视图,它被称为ContentView。与ContentPage类似,ContentView具有一个Con?tent属性,您可以将其设置为其他视图的可视树。您可以在代码中定义Con?tentView的内容,但在XAML中执行它更有趣。
让我们整理一个名为ColorViewList的解决方案。此解决方案将具有两组XAML和代码隐藏文件,第一个用于名为ColorViewListPage的类,它派生自ContentPage(通常),第二个用于派生自ContentView的名为ColorView的类。
要在Visual Studio中创建ColorView类,请使用与向ColorViewList项目添加新XAML页面时相同的过程:在解决方案资源管理器中右键单击项目名称,然后从上下文菜单中选择“添加”>“新建项”。在Add New Item对话框中,选择左侧的Visual C#> Cross-Platform,然后选择Forms Xaml Page。输入名称ColorView.cs。但是,在您忘记之前,立即进入ColorView.xaml文件并将ContentPage开始和结束标记更改为ContentView。在ColorView.xaml.cs文件中,将基类更改为ContentView。
在Xamarin Studio中,这个过程稍微容易一些。从ColorViewList项目的工具菜单中,选择“添加”>“新建文件”。在“新建文件”对话框中,选择左侧的“表单”和“表单ContentView Xaml”(不是“表单ContentPage Xaml”)。给它一个ColorView的名字。
您还需要像往常一样为ColorViewListPage类创建XAML文件和代码隐藏文件。
ColorView.xaml文件描述了各个颜色项的布局,但没有任何实际颜色值。相反,BoxView和两个Label视图的名称是:
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ColorViewList.ColorView">
<Frame OutlineColor="Accent">
<StackLayout Orientation="Horizontal">
<BoxView x:Name="boxView"
WidthRequest="70"
HeightRequest="70" />
<StackLayout>
<Label x:Name="colorNameLabel"
FontSize="Large"
VerticalOptions="CenterAndExpand" />
<Label x:Name="colorValueLabel"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</StackLayout>
</Frame>
</ContentView>
在现实生活中,您将有足够的时间来微调视觉效果。最初,您只想在那里获取所有命名视图。
除了视觉效果,此ColorView类还需要一个新属性来设置颜色。必须在代码隐藏文件中定义此属性。首先,为ColorView提供一个名为Color of Color的属性似乎是合理的(因为MyColorView的早期XAML片段似乎暗示)。但ColorView类需要显示颜色名称,并且无法从Color值中获取颜色名称。
相反,定义名为ColorName的类型为string的属性更有意义。然后,代码?后面的文件可以使用反射来获取与该名称对应的Color类的静态字段。
但是等待:Xamarin.Forms包含一个公共ColorTypeConverter类,XAML解析器使用该类将“Red”或“Blue”等文本颜色名称转换为Color值。为什么不利用这个呢?
这是ColorView的代码隐藏文件。它定义了一个带有set访问器的ColorName属性,该属性将colorNameLabel的Text属性设置为颜色名称,然后使用ColorType?Converter将名称转换为Color值。然后使用此Color值将boxView的Color属性和colorValueLabel的Text属性设置为RGB值:
public partial class ColorView : ContentView
{
string colorName;
ColorTypeConverter colorTypeConv = new ColorTypeConverter();
public ColorView()
{
InitializeComponent();
}
public string ColorName
{
set
{
// Set the name.
colorName = value;
colorNameLabel.Text = value;
// Get the actual Color and set the other views.
Color color = (Color)colorTypeConv.ConvertFrom(colorName);
boxView.Color = color;
colorValueLabel.Text = String.Format("{0:X2}-{1:X2}-{2:X2}",
(int)(255 * color.R),
(int)(255 * color.G),
(int)(255 * color.B));
}
get
{
return colorName;
}
}
}
ColorView类已完成。 现在让我们看一下ColorViewListPage。 ColorViewList?Page.xaml文件必须列出多个ColorView实例,因此它需要一个带有新名称空间前缀的新XML名称空间声明来引用ColorView元素。
ColorView类与ColorViewListPage属于同一个项目。 通常,程序员在这种情况下使用本地的XML名称空间前缀。 新的名称空间声明出现在XAML文件的根元素中(与其他两个一样),格式如下:
xmlns:local="clr-namespace:ColorViewList;assembly=ColorViewList"
在一般情况下,XAML的自定义XML名称空间声明必须指定公共语言运行时(CLR)名称空间(也称为.NET名称空间)和程序集。指定这些的关键字是clr-namespace和assembly。通常,CLR命名空间与组件相同,就像它们在这种情况下一样,但它们不需要。这两部分用分号连接。
请注意,冒号跟在clr-namespace之后,但是在程序集之后有一个等号。这种明显的不一致是有意的:名称空间声明的格式旨在模仿传统名称空间声明中的URI,其中冒号遵循URI方案名称。
您使用相同的语法来引用外部可移植类库中的对象。在这些情况下唯一不同的是项目还需要参考外部PCL。 (您将在第10章“XAML标记扩展”中看到一个考试。)。
本地前缀对于同一程序集中的代码是通用的,在这种情况下,不需要组装部件:
xmlns:local="clr-namespace:ColorViewList"
对于PCL中的XAML文件,如果需要,可以包括装配部件以引用与?装配相同的内容,但不是必需的。 但是,对于SAP中的XAML文件,您不得包含程序集部件以引用本地类,因为没有与SAP关联的程序集。 SAP中的代码实际上是各个平台程序集的一部分,并且这些代码都具有不同的名称。
这是ColorViewListPage类的XAML。 代码隐藏文件除了InitializeComponent调用之外什么都不包含:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ColorViewList"
x:Class="ColorViewList.ColorViewListPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness"
iOS="0, 20, 0, 0" />
</ContentPage.Padding>
<ScrollView>
<StackLayout Padding="6, 0">
<local:ColorView ColorName="Aqua" />
<local:ColorView ColorName="Black" />
<local:ColorView ColorName="Blue" />
<local:ColorView ColorName="Fuchsia" />
<local:ColorView ColorName="Gray" />
<local:ColorView ColorName="Green" />
<local:ColorView ColorName="Lime" />
<local:ColorView ColorName="Maroon" />
<local:ColorView ColorName="Navy" />
<local:ColorView ColorName="Olive" />
<local:ColorView ColorName="Purple" />
<local:ColorView ColorName="Pink" />
<local:ColorView ColorName="Red" />
<local:ColorView ColorName="Silver" />
<local:ColorView ColorName="Teal" />
<local:ColorView ColorName="White" />
<local:ColorView ColorName="Yellow" />
</StackLayout>
</ScrollView>
</ContentPage>
这并不像前面的例子所暗示的那样令人厌恶,它演示了如何将视觉效果封装在他们自己的基于XAML的类中。 请注意,StackLayout是ScrollView的子项,因此可以滚动列表:
但是,ColorViewList项目的一个方面不符合“最佳实践”。它是ColorView中ColorName属性的定义。 这应该实现为BindableProperty对象。 深入研究可绑定对象和可绑定属性是一个高优先级,将在第11章“可绑定基础结构”中进行探讨。