您自己的用户界面
如果您想提供自己的用户界面以在主视图和详细视图之间切换,您可能还希望禁用MasterDetailPage自动提供的界面。您可以通过两种方式执行此操作:
- 将IsGestureEnabled属性设置为false以禁用iOS和Android上的滑动手势支持。
- 重写受保护的ShouldShowToolbarButton方法并返回false以隐藏Windows 8.1和Windows Phone 8.1上的工具栏按钮。
但是,您将无法完全禁用该界面。将IsGestureEnabled属性设置为false意味着您无法再使用滑动在iOS和Android上的主控和详细信息之间切换。但是,该属性不会影响水龙头。对于iOS和Android,当显示器具有弹出行为并且母版页覆盖详细信息页面时,您可以通过点击右侧的详细信息页面来关闭母版页。 IsGestureEnabled不会禁用这些点击。
如果将IsGestureEnabled属性设置为false,则需要提供自己的用户界面,以便在iOS和Android的详细信息页面中显示主视图。
Windows 8.1和Windows Phone 8.1平台上的MasterDetailPage附带的工具栏按钮附加到底层本机页面。无法从MasterDetailPage的ToolbarItems集合或设置为Master和Detail属性的两个页面访问它。覆盖ShouldShowToolbarButton并返回false禁止该工具栏按钮。同样,如果您这样做,您必须提供自己的用户界面,以便在主视图和详细视图之间切换。
另一个问题是,当MasterDetailPage使用拆分模式时,根本不需要接口来切换视图。您知道在iPad和Windows运行时平板电脑上只能获得分割模式,但如果您将MasterBehavior指定为Default或SplitOnLandscape,您如何判断屏幕何时处于分屏模式或叠加模式?
在Windows运行时平板电脑上,对ShouldShowToolbarButton的基本实现的调用将告诉您。对于处于叠加模式的手机和平板电脑,此方法返回true,但对于分割模式下的平板电脑,它返回false。但是,此方法仅在Windows 8.1和Windows Phone 8.1上实现。
对于iOS,您可以通过检查页面的尺寸来确定iPad是处于叠加模式还是分割模式。如果页面处于纵向模式,则为叠加;对于横向模式,它是分裂的。
让我们使用所有这些知识。 ColorsDetails程序在母版页的ListView中显示NamedColor集合中的所有颜色,并在其详细信息页面中提供有关所选颜色的详细信息。这是首页的主页定义:
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit=
"clr-namespace:Xamarin.FormsBook.Toolkit;assembly=Xamarin.FormsBook.Toolkit"
x:Class="ColorsDetails.ColorDetailsPage"
IsPresented="True"
x:Name="page">
<MasterDetailPage.Master>
<ContentPage Title="Colors">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness"
iOS="0, 20, 0, 0" />
</ContentPage.Padding>
<ListView x:Name="listView"
SeparatorVisibility="None"
ItemsSource="{x:Static toolkit:NamedColor.All}"
ItemTapped="OnListViewItemTapped">
<ListView.RowHeight>
<OnPlatform x:TypeArguments="x:Int32"
iOS="80"
Android="80"
WinPhone="90" />
</ListView.RowHeight>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ContentView Padding="5">
<Frame OutlineColor="Accent"
Padding="10">
<StackLayout Orientation="Horizontal">
<BoxView x:Name="boxView"
Color="{Binding Color}"
WidthRequest="50"
HeightRequest="50" />
<StackLayout>
<Label Text="{Binding Name}"
FontSize="Medium"
VerticalOptions="StartAndExpand" />
<Label Text="{Binding RgbDisplay,
StringFormat='RGB = {0}'}"
FontSize="Small"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</StackLayout>
</Frame>
</ContentView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
</MasterDetailPage.Master>
__
</MasterDetailPage>
此ListView的标记与第19章的CustomNamedColorList程序中的标记非常相似。但是,在这个新版本中,ListView的ItemTapped事件在代码隐藏文件中处理。 (你很快就会看到这个代码。)
这是三个平台上的颜色列表:
用作详细信息视图的ContentPage将其BindingContext设置为ListView的SelectedItem属性。 大部分内容 - 包括BoxView的颜色; 红色,绿色和蓝色值; 和色调,饱和度和亮度值 - 在ScrollView中。 这是为横向模式的手机带来的好处。 此ScrollView中没有的唯一元素是一个Label,其页面顶部是颜色名称,底部是Button:
<MasterDetailPage __ >
__
<MasterDetailPage.Detail>
<NavigationPage>
<x:Arguments>
<ContentPage Title="Color"
BindingContext="{Binding Source={x:Reference listView},
Path=SelectedItem}">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness"
iOS="0, 20, 0, 0" />
</ContentPage.Padding>
<StackLayout>
<Label Text="{Binding FriendlyName}"
Style="{DynamicResource TitleStyle}"
HorizontalTextAlignment="Center" />
<ScrollView VerticalOptions="FillAndExpand">
<StackLayout>
<BoxView Color="{Binding Color}"
WidthRequest="144"
HeightRequest="144"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" />
<StackLayout VerticalOptions="CenterAndExpand"
HorizontalOptions="Center">
<StackLayout.Resources>
<ResourceDictionary>
<Style TargetType="Label">
<Setter Property="HorizontalTextAlignment"
Value="End" />
</Style>
</ResourceDictionary>
</StackLayout.Resources>
<Label Text="{Binding Color.R,
StringFormat='Red = {0:F2}'}" />
<Label Text="{Binding Color.G,
StringFormat='Green = {0:F2}'}" />
<Label Text="{Binding Color.B,
StringFormat='Blue = {0:F2}'}" />
<Label Text="{Binding Color.A,
StringFormat='Alpha = {0:F2}'}" />
<Label Text=" " />
<Label Text="{Binding Color.Hue,
StringFormat='Hue = {0:F2}'}" />
<Label Text="{Binding Color.Saturation,
StringFormat='Saturation = {0:F2}'}" />
<Label Text="{Binding Color.Luminosity,
StringFormat='Luminosity = {0:F2}'}" />
</StackLayout>
</StackLayout>
</ScrollView>
<Button x:Name="returnButton"
Text="Return to list"
HorizontalOptions="Center"
Clicked="OnReturnButtonClicked">
<Button.IsEnabled>
<Binding Source="{x:Reference page}"
Path="IsPresented">
<Binding.Converter>
<toolkit:BooleanNegationConverter />
</Binding.Converter>
</Binding>
</Button.IsEnabled>
</Button>
</StackLayout>
</ContentPage>
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Detail>
</MasterDetailPage>
当然,底部的Button在代码隐藏文件中有一个Clicked事件处理程序,但也注意到绑定到其IsEnabled属性的数据。 数据绑定的来源是MasterDetailPage的IsPresented属性。 如果IsPresented为true - 表示显示主视图 - 则禁用Button。 (如果你想在代码中做类似的事情,MasterDetailPage定义了一个IsPresentedChanged事件。)
您可以在详细信息视图底部看到按钮以返回到主视图:
代码隐藏文件处理ListView和Button的事件处理程序(朝向文件的底部)。 这些仅将IsPresented属性分别设置为false和true,并且当MasterDetailPage处于拆分模式时无效:
public partial class ColorDetailsPage : MasterDetailPage
{
public ColorDetailsPage()
{
InitializeComponent();
IsGestureEnabled = false;
// Special processing for iPads.
if (Device.OS == TargetPlatform.iOS &&
Device.Idiom == TargetIdiom.Tablet)
{
SizeChanged += (sender, args) =>
{
// Enable button for portrait mode.
returnButton.IsVisible = Height > Width;
};
}
}
public override bool ShouldShowToolbarButton()
{
// Only works for Windows and Windows Phone platforms.
returnButton.IsVisible = base.ShouldShowToolbarButton();
return false;
}
void OnListViewItemTapped(object sender, ItemTappedEventArgs args)
{
IsPresented = false;
}
void OnReturnButtonClicked(object sender, EventArgs args)
{
IsPresented = true;
}
}
代码隐藏文件中更有趣的部分是构造函数和ShouldShowToolbarButton的重写。这些代码段尝试两个作业:
首先,他们通过将IsGestureEnabled设置为false并从ShouldShowToolbarButton返回false来禁用现有用户界面以在主视图和详细视图之间切换。这意味着Windows 8.1和Windows Phone 8.1平台上不显示任何工具栏项。 MasterDetailPage仍然要求在作为主视图的ContentPage上设置标题,但该标题不会在这些平台上的任何位置使用。
第二项工作是在MasterDetailPage处于拆分视图时完全隐藏该Button。当程序在iPad上运行时,页面的SizeChanged处理程序在构造函数中设置,并且仅当页面尺寸指示纵向模式时才将IsVisible属性设置为true。如果ShouldShowToolbarButton的基本实现返回true,则ShouldShowToolbarButton覆盖通过显示Button来处理Windows平板电脑。
这是实现您自己的用户界面以在主视图和详细视图之间切换的一种方法。 MasterDetailTaps计划显示了另一种方法。此程序类似于本章开始的MasterDetailBehavior程序,但主要和详细视图的定义合并在一个XAML文件中。此新程序禁用现有UI以在主视图和详细视图之间进行转换,并使用简单的点击替换它。
MasterDetailTapsPage派生自MasterDetailPage,并包含与早期程序类似的Frame和Label元素:
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MasterDetailTaps.MasterDetailTapsPage"
Title="Demo Page">
<MasterDetailPage.Master>
<ContentPage Title="Master"
Padding="10"
x:Name="masterPage">
<Frame OutlineColor="Accent"
BackgroundColor="Transparent">
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="OnMasterTapped" />
</Frame.GestureRecognizers>
<StackLayout Orientation="Horizontal"
Spacing="0"
HorizontalOptions="Center"
VerticalOptions="Center">
<Label Text="{Binding Source={x:Reference masterPage},
Path=Width,
StringFormat='Master: {0:F0}'}"
FontSize="Large" />
<Label Text="{Binding Source={x:Reference masterPage},
Path=Height,
StringFormat=' × {0:F0}'}"
FontSize="Large" />
</StackLayout>
</Frame>
</ContentPage>
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage>
<x:Arguments>
<ContentPage Title="Detail"
Padding="10"
x:Name="detailPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness"
iOS="0, 20, 0, 0" />
</ContentPage.Padding>
<Frame OutlineColor="Accent"
BackgroundColor="Transparent">
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="OnDetailTapped" />
</Frame.GestureRecognizers>
<StackLayout Orientation="Horizontal"
Spacing="0"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center">
<Label Text="{Binding Source={x:Reference detailPage},
Path=Width,
StringFormat='Detail: {0:F0}'}"
FontSize="Large"/>
<Label Text="{Binding Source={x:Reference detailPage},
Path=Height,
StringFormat=' × {0:F0}'}"
FontSize="Large" />
</StackLayout>
</Frame>
</ContentPage>
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Detail>
</MasterDetailPage>
请注意TapGestureRecognizer附加到主页面和详细信息页面上的Frame元素。
另请注意,每个Frame的BackgroundColor都设置为Transparent。 这是为了Windows平台的好处。 这些平台中Frame的默认背景为null,这使得抽头可以通过底层元素。 将背景设置为“透明”不会更改外观,但会捕获点击。
Tapped处理程序只需设置IsPresented:
public partial class MasterDetailTapsPage : MasterDetailPage
{
public MasterDetailTapsPage()
{
InitializeComponent();
// Disable swipe interface.
IsGestureEnabled = false;
}
public override bool ShouldShowToolbarButton()
{
// Hide toolbar button on Windows platforms.
return false;
}
void OnMasterTapped(object sender, EventArgs args)
{
// Catch exceptions when setting IsPresented in split mode.
try
{
IsPresented = false;
}
catch
{
}
}
void OnDetailTapped(object sender, EventArgs args)
{
IsPresented = true;
}
}
普通用户界面与前一个程序一样被禁用,但在分离模式下隐藏新用户界面不需要逻辑。
OnMasterTapped方法中的try和catch块用于避免在拆分模式下在Windows和iPad上发生的InvalidOperationException。 异常附带的错误消息指出“设置拆分时无法更改IsPresented”。