Silverlight 教程:使用 Storyboards 创建动画导航栏






4.07/5 (8投票s)
系列文章的第一篇。本文重点介绍如何使用 Storyboards 来创建动画效果。
请点击此链接查看此项目的最终运行效果演示。

引言
本文是一个教程,介绍如何使用 Silverlight 2.0 创建一个类似于 Silverlight.net 网站顶部(以及我自己的网站 SilverlightWebApps.com 顶部)的精美动画导航栏。当鼠标悬停在您想要导航到的标题上时,背景会亮起并发出辉光,同时三角形指针会缩放到您指向的项。当您单击导航项时,Silverlight 页面上的内容面板将被替换为新选定的内容。
本文是系列文章的第一篇。在本篇文章中,我将重点介绍如何手动将 Storyboards 连接到鼠标事件,在第二篇文章中,我将展示如何使用 Visual State Manager 来实现这一点。
分步教程
简要说明
- 在 VS2008 中创建一个名为
TutorialNavbar
的空网站 - 添加新项,选择 Silverlight 应用程序,并将项目保存为 TutorialNavbarXap.csproj
- 选择“创建新的 Silverlight 项目”选项并将其添加到解决方案中
- 删除 VS2008 自动生成的 TutorialNavbarTestPage.aspx 文件。保留 TutorialNavbarTestPage.html 页面。我之所以喜欢从 Visual Studio 网站项目开始,而不是从 Expression Blend 项目开始,原因如下:
- 在我看来,在 Expression Blend 中打开 C# 文件时,Intellisense 不起作用(至少在 Expression Blend 2.5 June Preview 版本中是这样——希望在正式发布版中会得到解决)。
- 我认为您无法调试纯 Expression Blend 项目,而如果您像我上面描述的那样从 VS2008 项目开始,则断点可以正常工作。
- Expression Blend 会创建自己的默认测试页面,您对此页面无法进行控制。这可能是一个问题,例如,如果您有一个页面比浏览器窗口大,默认的 Expression Blend 页面将没有滚动条。通过像我上面描述的那样创建项目,您可以根据需要修改样式表来添加这些元素。
理论上,VS2008 和 Expression Blend 会协同工作并保持同步,这样您就可以在 VS2008 和/或 Expression Blend 环境中无缝地编辑文件,而不会遇到任何问题。但实际上,我曾遇到过这两个环境不同步的情况,您会发现从 Expression Blend 中按 F5 运行的项目在 VS2008 中却无法运行。要恢复同步,请确保 Expression Blend 中所有文件都已保存,按 F5 进行构建,然后从 VS2008 中尝试“构建”->“清理解决方案”,再“构建”->“重新生成全部”。
- 在 Expression Blend 2.5 June Preview 中打开新创建的项目
TutorialNavbarXap
- 创建一个在视觉上看起来与下图相似的内容。注意,为了获得绿色的背景高亮效果,我选择了一个径向渐变画笔,并将右侧停止点的透明度设置为 30%。将三角形指针命名为
NavIndicator
,并将每个绿色高亮命名为Nav1Highlight
、Nav2Highlight
、Nav3Highlight
。 - 在主页面上添加一个占据大部分页面的 Canvas,并将其命名为
ContentCanvas
- 创建一个矩形,该矩形覆盖了
Nav1Highlight
的整个绿色高亮区域以及箭头所在区域的下方。将此区域命名为Nav1ClickArea
。复制此矩形以创建Nav1
和Nav2
,并相应地命名。将每个区域的不透明度设置为 0%。顾名思义,这是您将要单击以进行导航的区域。 - 创建一些占位符页面以供导航。在 Expression Blend 中,转到项目视图,单击项目,然后选择“添加新项”。将项命名为 Nav1Page.xaml,并勾选“包含代码文件”复选框。对 Nav2Page.xaml 和 Nav3Page.xaml 重复此操作。在 Nav1Page.xaml 中,添加一个文本块,内容为“
Nav1Page
占位符”。对Nav2Page
和Nav3Page
重复此操作,并相应更改文本内容。 - 选择
Nav1ClickArea
,转到属性,选择事件按钮(闪电图标),然后在MouseLeftButtonDown
事件下输入方法名OnNav1Click
。 - 按 Enter 键后,VS2008 应该会启动,您会发现 Expression Blend 已在 page.xaml.cs 文件中输入了以下空方法。对
Nav2ClickArea
和Nav3ClickArea
重复上述步骤。private void OnNav1Click(object sender, MouseButtonEventArgs e) { }
- 我们正在创建将要显示的每个页面的实例。
- 我们将
PageLoaded
方法附加到Loaded
事件,并使用该方法将Nav1Page
设置为默认页面。 - 我们添加了代码到
OnNavClick
方法中,用于移除先前显示的页面并添加新页面。
public partial class Page : UserControl { Nav1Page m_nav1Page = new Nav1Page(); Nav2Page m_nav2Page = new Nav2Page(); Nav3Page m_nav3Page = new Nav3Page(); public Page() { InitializeComponent(); Loaded += new RoutedEventHandler(PageLoaded); } void PageLoaded(object sender, RoutedEventArgs e) { RemoveAll(); ContentCanvas.Children.Add(m_nav1Page); } void RemoveAll() { ContentCanvas.Children.Remove(m_nav1Page); ContentCanvas.Children.Remove(m_nav2Page); ContentCanvas.Children.Remove(m_nav3Page); } private void OnNav1Click(object sender, MouseButtonEventArgs e) { RemoveAll(); ContentCanvas.Children.Add(m_nav1Page); } private void OnNav2Click(object sender, MouseButtonEventArgs e) { RemoveAll(); ContentCanvas.Children.Add(m_nav2Page); } private void OnNav3Click(object sender, MouseButtonEventArgs e) { RemoveAll(); ContentCanvas.Children.Add(m_nav3Page); } }
- 构建并调试。您应该会看到,当您单击每个区域时,指定的页面就会出现。
- 现在让我们让高亮显示出现。如上所示,使用
MouseLeftButtonDown
事件,将OnNav1Enter
方法名添加到MouseEnter
事件。对Nav2
和Nav3
重复此操作。 - 创建一个
HighlightNone
方法来使所有高亮显示不可见,然后从PageLoaded
方法中调用它。然后在OnNavEnter
方法中,调用HighlightNone
,然后调用使选定项高亮显示的方法。以下代码片段对此进行了说明:void PageLoaded(object sender, RoutedEventArgs e) { // Remove all content add then add the Nav1Page RemoveAll(); ContentCanvas.Children.Add(m_nav1Page); // Highlight Nav1 HighlightNone(); Nav1Highlight.Opacity = 100.0; } private void HighlightNone() { Nav1Highlight.Opacity = 0.0; Nav2Highlight.Opacity = 0.0; Nav3Highlight.Opacity = 0.0; } private void OnNav1Enter(object sender, MouseEventArgs e) { HighlightNone(); Nav1Highlight.Opacity = 100.0; } private void OnNav2Enter(object sender, MouseEventArgs e) { HighlightNone(); Nav2Highlight.Opacity = 100.0; } private void OnNav3Enter(object sender, MouseEventArgs e) { HighlightNone(); Nav3Highlight.Opacity = 100.0; }
- 构建并调试。您应该会看到,每当您鼠标悬停在不同的导航区域上时,高亮显示就会出现。
- 现在我们来为
NavIndicator
三角形添加动画。创建一个名为MoveToNav2
的 storyboard。 - 不设置零时刻的关键帧,将时间轴移动到 1 秒,然后将
NavIndicator
三角形拖动到Nav2
下方的居中位置。 - 单击
NavIndicator
的关键帧标记,并将缓动效果调整为 x1=0 和 x2=.5。如果您在单击NavIndicator
关键帧时未看到下方的缓动框,请确保属性框设置为“属性”而不是“事件”。播放 storyboard 以查看这些调整的效果。完成后关闭 storyboard。 - 现在转到 XAML 视图,查看为该 storyboard 生成的代码。您将看到两个以
DoubleAnimationUsingKeyFrames
开头的节。第一个动画化 X 方向,如以下行所示:Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)
第二个DoubleAnimationUsingKeyFrames
动画化 Y 方向,如TranslateTransform.Y
项所示。我们只想让NavIndicator
水平移动,因此删除第二个DoubleAnimationUsingKeyFrames
部分。 - 现在复制整个 storyboard,但更改两处内容:
- 将 storyboard 的名称更改为
MoveToNav1
,如下所示:<Storyboard x:Name="MoveToNav1">
- 将
SplineDoubleKeyFrame Value
更改为0
,如下所示:<SplineDoubleKeyFrame KeyTime="00:00:01" Value="0">
这样做是创建了一个相同的 storyboard,但它不是移动到
Nav2
位置,而是移动回原来的位置(即0
)。我们将对MoveToNav3
执行相同的操作。Nav3
的值是如何移动的?我实际上创建了一个使用“对象和时间线”菜单的MoveToNav3
storyboard,读取了 X 移动的值,然后将该值复制到我基于上述MoveToNav2
storyboard 创建的自己的 XAML storyboard 中。如果您不想处理 XAML,您可以为上面的原始MoveToNav2
storyboard 重复上述步骤,为每个其他移动操作执行相同的操作。 - 将 storyboard 的名称更改为
- 现在添加代码,以便在鼠标经过导航区域时启动相应的动画。
private void OnNav1Enter(object sender, MouseEventArgs e) { HighlightNone(); Nav1Highlight.Opacity = 100.0; MoveToNav1.Begin(); } private void OnNav2Enter(object sender, MouseEventArgs e) { HighlightNone(); Nav2Highlight.Opacity = 100.0; MoveToNav2.Begin(); } private void OnNav3Enter(object sender, MouseEventArgs e) { HighlightNone(); Nav3Highlight.Opacity = 100.0; MoveToNav3.Begin(); }
- 嗯……一秒钟对于这个过渡来说有点慢。让我们将过渡时间改为 0.5 秒。转到 XAML,将时间从 1 秒更改为半秒。
<Storyboard x:Name="MoveToNav1"> <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"… <SplineDoubleKeyFrame KeyTime="00:00:00.50" Value="0">
- 好多了!就是这样。现在您已经有了一个动画导航栏。
历史
- 2008 年 7 月:第一次修订
- 2008 年 8 月:更新以引用系列文章的第二篇