导航

  • 通过使用导航 API,您可以使用 Navigate 和 GoBack 方法。 这两个方法可向导航历史记录(Back 堆栈)推入或从其弹出一个 URL。 由于没有 API 用于管理 Back 堆栈,因此您必须自己管理瞬时屏幕。 瞬时屏幕指您不想让用户在按“后退”键时再访问的对话框或提示,例如消息提示或登录对话框。
  • Windows Phone 一次只允许一个导航是活动的。 如果您需要“回到主页”功能(通常是可让用户向回导航多个页面的快捷方式),则需要对一系列 GoBack 方法调用逐一进行序列化;这会影响您的 UX。
  • 两个导航参与者 PhoneApplicationPage 和 PhoneApplicationFrame 对页面过渡都不具有现成的支持。

让我们详细解析这些方面的问题,以便最终能够获得可行的解决方法。

瞬时内容

瞬时屏幕是不能加入到日志 Back 堆栈(日志历史记录)的屏幕,例如登录对话框。 用户从某页面导航至登录对话框,但在他们继续向前然后又按“后退”键时,您不想让用户回到该对话框,而想让他们回到该对话框的前一屏幕。

有几种方法来创建和显示瞬时屏幕。 一个显而易见的方法是使用 Silverlight Popup 显示 UI。 关于 Popup 方法有两个小问题:

  1. Popup 不能识别方向。这不是一个大问题;您可以写一个能够识别方向的 Popup,或者只需将 Popup 插入可视化树中,然后它会根据页面方向进行布局。
  2. 全屏 Popup 中的内容不会经过硬件加速。 对于登录对话框 UI(以及很多瞬时页面),这个方法会有效。但是假如 Popup 有一个含有需要滚动才能显示所有项目的 ListBox,或是它有一个动画的 ProgressBar 时,您就会希望对 Popup 进行硬件加速,从而实现您的 UI 线程的最佳响应。

由于存在这些小问题,我们建议您使用高于所在页面内容的 z 索引,通过将 UI 插入可视化树来实现 UI 的内联。 分步实现方法如下:

  1. 将想要内联至可视化树的内容打包到一个用户控件中,以便能够将其插入可视化树并在页面中显示它(不与页面的 UI 混合)。
  2. 在要显示 UI 的 PhoneApplicationPage 中,处理 OnBackKeyPress 回调或 BackKeyPress 事件,以在按“后退”按钮时禁止显示瞬时 UI(不向后导航)。
    1. 具有多个状态(展开和折叠)的自定义控件应公开属性,以便宿主页面能够查询它们的状态,了解它们是否处于可以使用“后退”按钮按下事件的状态(如果适用)。 例如,控件工具箱中的 ListPicker 具有 ListPickerMode 属性,ContextMenu 具有 IsOpen 属性,等等。
  3. 在显示瞬时 UI 时,隐藏页面中的 ApplicationBar(如果适用)。 ApplicationBar 由操作系统绘制,当它不透明时 (Opacity = 1.0) 时,会在页面内容区域下方预留一些空间。 如需将瞬时 UI 模拟显示为新屏幕,您很可能想要隐藏该应用程序栏。
  4. 动画显示瞬时 UI 的进入和退出,以便与应用程序的余下 UX 浑然一体(如果适用)。

代码演练: 要查看瞬时 UI 屏幕,请在随附的代码下载中查看 TransientUISample.xaml.cs,注释中列出了步骤说明。

前述大部分要求都直观易懂;只有一个需要解释的是 2.a。 为满足认证要求,显示瞬时屏幕的 PhoneApplicationPage 在显示瞬时 UI 时不应向后导航。 它应该取消显示该瞬时 UI。

本文的第 1 部分提到过,您应通过处理 OnBackKeyPress 或 BackKeyPress 事件禁止硬件“后退”导航。 如果您的页面正承载一个有两个状态的控件,其中一个状态是瞬时的,那么需要在该页面与控件之间做些协调(至少要了解)。 要实现这种交流,我们建议:

  1. 有多个状态的自定义控件(例如,ListPicker)应在它们的宿主页面上订阅 BackKeyPress 并合理处理该事件。 它们若正处于瞬时状态,则应取消“后退”键按下事件,并取消它们的瞬时状态。
    1. 这些控件应只在需要时进行订阅。 对 BackKeyPress 事件的订阅应延迟到需要时再进行。
    2. 我们习惯让控件沿可视化树上行来查找它们的 PhoneApplicationPage,但我们见过有专家(例如控件工具箱团队)通过访问应用程序 RootVisual(就是我们知道的 PhoneApplicationFrame)探知它的内容。 这样做性能当然更高,且仍然安全,因为我们知道在一个 Silverlight 应用程序中只有一个 UI 线程(所以 RootVisual 不大可能在您的控件或页面的事件处理程序中发生更改)。
  2. 自定义控件和瞬时 UI 应公开属性,以便宿主页面能够查询它们的状态,了解它们是否处于能够使用“后退”按钮按下事件的状态。 例如,控件工具箱中的 ListPicker 具有 ListPickerMode 属性,ContextMenu 具有 IsOpen 属性,等等。
  3. 在 OnBackKeyPress 中执行任何导航之前,宿主 PhoneApplicationPage 需要了解能够显示的任何瞬时控件或 UI 并对它们进行检查。请记住,在调用任何 BackKeyPress 事件处理程序之前都会先调用 OnBackKeyPress。 如果依靠驻留的控件处理它们的瞬时状态,则要确保不要调用 Navigate 方法,并位于处理程序之前。

“主页”按钮导航(以及清空 Back 堆栈)

其他移动平台的一个常见 UX 模式是使用一个“主页”按钮,该按钮作为导航快捷方式将用户送往特定页面。Windows Phone 导航 API 不直接提供该功能;实际上,UX 指南非常不主张使用“主页”按钮。 建议的做法是使用一个经过良好设计且相对平缓的导航结构。 如果您的导航深度只有两三层,可能多按几次硬件“后退”按钮也一样简单,因为在屏幕上找到“主页”按钮再点击它需要更多的搜寻和定位操作。 也就是说,如果您选择使用“主页”按钮,在实现导航时须考虑几件事:

  • 请记住 Windows Phone 一次只允许一个导航。 这意味着如果您的导航深度有四层,就需要连续调用 GoBack 三次才能返回主页。 由于不允许并行导航,您必须等到一个导航完成后(即触发“Navigated”事件后),才能开始下一个导航。 如果您的页面加载时间较长,这种“顺序导航”会导致短暂的延迟;或是,如果在页面可视时弹出 Back 堆栈,则可能导致“闪烁”。
  • ApplicationBar 的动画处理由操作系统实现。 这意味着如果您正在几个页面间循环导航,当 ApplicationBar 以动画形式在其中一个页面显示时,UI 可能再次闪烁。

所以,在这里给出一个方法来解决“主页”导航的问题。 您可以在随附的下载内容中查看通过 BackNavigationHelper 类实现的所有这些代码:

  1. 在弹出 Back 堆栈时,从屏幕上隐藏 PhoneApplicationFrame(应用程序的 RootVisual)。 这会防止 UI 闪烁(它会闪烁一次,但不会有所有屏幕后退的现象)。
    1. 如果页面费时太久,那么您可以使用动画全屏显示 Popup,以便用户知道正在发生的情况。
    2. 您还应在主页导航开始前设置一个标记,这样页面就知道在 OnNavigatedTo 回调时不做太多工作。如果您正向后导航,则在导航完成时会卸载这些页面(这样会丢弃它们正做的任何 UI 工作)。
  2. 如果情况允许,在每个展开的页面中隐藏 ApplicationBar(通过将其 IsVisible 属性设置为 false)。
    1. 请注意,此要求只针对 ApplicationBar 是 100% 不透明(其 Opacity = 1.0)的页面。
  3. 展开堆栈。
    1. 调用 GoBack 方法。
    2. 如果尚未进入“主页”页面,则侦听 Navigated(在 RootVisual 上)并再次调用 GoBack。

展开堆栈后,将全部内容重置为正常。

代码演练: 在随附的代码下载中,您会看到 HomeNavigationSamplePages 文件夹的页面中提供了“返回主页”导航示例。当然,相关代码主要是在 BackNavigationHelper 类中,但是我们的示例有一个 BackNavConfig 页面,在这里您能选择想要在 BackNavigationHelper(如隐藏框架、隐藏应用程序栏、验证日志等等)中启用的选项。

页面过渡

您关心的最后一个也是最高级的导航概念可能在于页面过渡。 在导航上下文中,我们将过渡理解为从当前页面导航至目标页面的移交过程。 导航仍在进行,使用的是我们之前讨论过的底层导航框架。但随着导航的发生,参加导航的 PhoneApplicationPage 的内容会动画模拟移交。

过渡的方法有一点儿复杂。 实际上,这就像奶奶的千层面,不是只有一种做法,而是要根据您的口味(和应用需要)进行“调整”。 鉴于此,我们提出几项基本原则,当然,还有一个示例和代码演练。

原则:

  1. 遵守前面讨论过的所有“后退”按键的规则。 再次强调,过渡只是导航的扩展,而不是认证失败的借口。
  2. 理解过渡动画的上下文和目的。 Windows Phone 提供完善定义的过渡集,其中大部分都有特定的上下文或使用方法。 您必须理解这些过渡的目标用途,才能在应用程序中实现正确的过渡。 Jeff Arnold(Windows Phone 主要动画设计师)对全部动画和过渡做了录制简介,是理解每个动画的必看内容。 您可以在 bit.ly/eBTkjD 找到该视频。
  3. 实现简短快速的过渡。
    1. 请记住过渡是“离开”一个页面并“进入”另一个页面的两阶段过程。 这两个阶段将会叠加。 应使它们尽量简短。 我们认为总时间 300 毫秒是合理的上限。
    2. 在过渡的过程中尽可能延迟 UI 工作。 如果您的页面能够避免数据绑定或高昂的布局操作,请考虑这样做。 您可以先完成屏幕过渡,此后迅速填充它。

图 1 摘要显示了动画和动画的用法、指令及相关说明。

图 1 动画摘要

动画 用法 指令 过渡说明
旋转栅 将用户从一个空间转至另一个空间。 设备默认应用。 强调过渡发生的常用设计。 ForwardIn、ForwardOut、BackwardIn 和 BackwardOut 这将是您较常使用的动画。 它的特点是非常直观。
连续体 将用户从一个空间过渡至另一空间,但过渡在感觉上是连续的。将上下文从一个空间转移至另一个空间。 但感觉像是没有空间变化。 In、Out 连续体也很常用,但较难实现。 它要求转移连续体上下文(可以认为携带 UIElement 在两个页面转移)。
转动 用于瞬时 UI,例如对话框。 与其他动画不同,它并不执行过渡,而是将用户留在同一空间中,或至少让人感觉是这样。 ForwardIn、ForwardOut、FullScreenIn、FullScreenOut、BackwardIn、BackwardOut 过渡中不常使用;多用于对话框。
幻灯片 用于瞬时 UI。 将内容覆盖到现有内容上。 SlideUpFadeIn、SlideUpFadeOut、SlideDownFadeIn、SlideDownFadeOut、SlideLeftFadeIn、SlideLeftFadeOut、SlideRightFadeIn、SlideRightFadeOut 常用于瞬时 UI 的过渡。
旋转 沿特定方向和角度旋转屏幕。 In90Clockwise、In90CounterClockwise、In180Clockwise、In180CounterClockwise、Out90Clockwise、Out90CounterClockwise、Out180Clockwise、Out180CounterClockwise 过渡中不常使用;多用于方向定位。

以前面列出的三条原则为指导,现在我们可以进行编码以执行页面过渡。 Windows Phone 控件工具箱提供对过渡的支持,并提供 Storyboards 用于最常用的过渡。

注意:本文余下内容的进行需要 Silverlight for Windows Phone 工具箱 (silverlight.codeplex.com)。 本文代码是针对二月发布的版本编写的(应该也适用于后面的版本)。

工具箱过渡使用继承自 PhoneApplicationFrame 的 TransitionFrame,但它包含带两个内容表示器的自定义模板(而 PhoneApplicationFrame 只有一个内容表示器)。 TransitionFrame 帧听对它的 Content 属性的更改,实现新旧 Content(页面)的过渡。

每个 PhoneApplicationPage 通过工具箱的 TransitionService 类中的附加属性,决定它需要的过渡。 可以为每页最多指定四个过渡,如图 2 所示。

图 2 可以指定的四个页面过渡

过渡(属性名称) 说明
NavigationInTransition.Forward 通过向前导航进入此页面时调用。
NavigationInTransition.Backward 当用户触发向后导航至此页面的操作时调用。
NavigationOutTransition.Forward 通过向前导航离开此页面时调用。
NavigationOutTransition.Backward 通过向后导航离开此页面时调用。

这些过渡是可扩展 NavigationTransition 类的实例。 该工具箱包含五个内置的 NavigationTransition:TurnstileTranstion、SlideTransition、SwivelTransition、RotateTransition 和 RollTransition。 同样,该系统是可扩展的,所以您可以添加自己的内容。

使用该工具箱实现过渡的分步指导:

1. 下载 Silverlight 控件工具箱并添加对它的引用。

2. 替换您的应用程序的 RootVisual 框架,方法是编辑 App.xaml.cs 并用 TransitionFrame 替换该框架(参见图 3)。

3. 对页面应用过渡属性(参见图 4)。

图 3 通过编辑 App.xaml.cs 替换应用程序的 RootVisual 框架


  
  
  1.  
  2.           private void InitializePhoneApplication()
  3.   {
  4.     if (phoneApplicationInitialized)
  5.         return;
  6.  
  7.     // Create the frame but don't set it as RootVisual yet; this allows the splash
  8.     // screen to remain active until the application is ready to render.
  9.           RootFrame = new Microsoft.Phone.Controls.TransitionFrame();
  10.     RootFrame.Navigated += CompleteInitializePhoneApplication;
  11.  
  12.     // Handle navigation failures
  13.     RootFrame.NavigationFailed += RootFrame_NavigationFailed;
  14.  
  15.     // Ensure we don't initialize again
  16.     phoneApplicationInitialized = true;
  17.   }
  18.         

图 4 对页面应用过渡属性


  
  
  1.  
  2.           <phone:PhoneApplicationPage 
  3.     x:Class="LWP.TransitionSamples.Turnstile"
  4.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  5.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  6.     xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
  7.     xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
  8.     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  9.     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  10.     FontFamily="{StaticResource PhoneFontFamilyNormal}"
  11.     FontSize="{StaticResource PhoneFontSizeNormal}"
  12.     Foreground="{StaticResource PhoneForegroundBrush}"
  13.     SupportedOrientations="Portrait" Orientation="Portrait"
  14.     mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
  15.     shell:SystemTray.IsVisible="True"  xmlns:toolkit=
  16.     "clr-namespace:Microsoft.Phone.Controls;assembly=
  17.     Microsoft.Phone.Controls.Toolkit"
  18.   >
  19.  
  20.   <toolkit:TransitionService.NavigationInTransition>
  21.     <toolkit:NavigationInTransition>
  22.       <toolkit:NavigationInTransition.Backward>
  23.         <toolkit:TurnstileTransition Mode="BackwardIn"/>
  24.       </toolkit:NavigationInTransition.Backward>
  25.       <toolkit:NavigationInTransition.Forward>
  26.         <toolkit:TurnstileTransition Mode="ForwardIn"/>
  27.       </toolkit:NavigationInTransition.Forward>
  28.     </toolkit:NavigationInTransition>
  29.   </toolkit:TransitionService.NavigationInTransition>
  30.   <toolkit:TransitionService.NavigationOutTransition>
  31.     <toolkit:NavigationOutTransition>
  32.       <toolkit:NavigationOutTransition.Backward>
  33.         <toolkit:TurnstileTransition Mode="BackwardOut"/>
  34.       </toolkit:NavigationOutTransition.Backward>
  35.       <toolkit:NavigationOutTransition.Forward>
  36.         <toolkit:TurnstileTransition Mode="ForwardOut"/>
  37.       </toolkit:NavigationOutTransition.Forward>
  38.     </toolkit:NavigationOutTransition>
  39.   </toolkit:TransitionService.NavigationOutTransition>
  40.         

可行性方法

总结起来,Windows Phone Silverlight 应用程序有一个 Web 类型的导航模型,这个模型使您可以从一个页面过渡出来,并有日志记录(或历史记录)功能用于访问以前的页面。 该导航模型具有即用性、易用性和相对完整性的特点。 有几个高级导航任务(如瞬时 UI、过渡或“回到首页”功能)都没有现成可用的实现,但本文分两部分向您介绍了在实现这些更高级任务时应该考虑的设计问题,并提供了简明、可操作的实现方法

http://msdn.microsoft.com/zh-cn/magazine/gg983484.aspx

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值