SilverLight之路(十三)

经过前面一十二回的介绍,我们这个项目已经有了一些效果,但至今还没有一点动画元素,上一节最后,我想尝试一下动画效果,结果还失败了。不过也正是以此为契机,使我在动画方面有了一些实践,这一节我们试着做一些动画效果出来。

比如当点击基金名称后,以一个翻转效果切换到基金详情页面

 

 

呵呵,虽然比较丑,但我们关注的是实现,毕竟不是美工嘛。

按照我们一贯的风格,不去介绍长篇大论的理论与基础,我们还是以动手实践为主。

提到动画,自然就会想到Storyboard,没错,它是一切动画的基础,除非你自己写计时器去自己控制。那我们就先建一个Storyboard!在哪建呢?我们的动画过渡是要在行情与详情页面间做切换,自然动画就要建立在它们的父级,也就是“基金行情”项目的MainPage中了。(再强调一下,我们是以学习为主,并不是在做项目,因此我们这里没有用什么模式,只以简单实现为主)

看一下动画的实现原理,应该很自然就可以想到,用一个动画控制一个容器旋转,转到垂直角度后,把容器中的控件换成目标控件,再把容器用另一个动画还原回原来的状态。这里为什么要用两个动画来实现,是因为我们可以在第一个动画的结束事件里来做切换控件的动作,而除了Completed事件外,我还真没找到还有其它事件。

 

回顾一下我们的MainPage结构

 

 

SVMain就是我们的容器,它是一个ScrollViewer,因为不同的功能页面大小是不同的,所以使用ScrollViewer做为容器可以解决滚动问题,那么我们的动画就是设置它翻转就可以了。第一个动画Storyboard_GoToDetails

 

我们在0秒与1秒的位置插入关键帧,并设置1秒处的SVMain的旋转角度为-90度,如

 

接下来创建第二个动画Storyboard_GoToDetails_Second

效果与第一个相反,即在第0秒的位置,设置SVMain的旋转角度为-90度,在第1秒的位置还原

动画的代码全由Blend自动生成,如下

 

View Code
<UserControl.Resources>

<Storyboard x:Name="Storyboard_GoToDetails">

<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationX)" Storyboard.TargetName="SVMain">

<EasingDoubleKeyFrame KeyTime="0" Value="0"/>

<EasingDoubleKeyFrame KeyTime="0:0:1" Value="0"/>

</DoubleAnimationUsingKeyFrames>

<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)" Storyboard.TargetName="SVMain">

<EasingDoubleKeyFrame KeyTime="0" Value="0"/>

<EasingDoubleKeyFrame KeyTime="0:0:1" Value="-90"/>

</DoubleAnimationUsingKeyFrames>

</Storyboard>

<Storyboard x:Name="Storyboard_GoToDetails_Second">

<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)" Storyboard.TargetName="SVMain">

<EasingDoubleKeyFrame KeyTime="0" Value="90"/>

<EasingDoubleKeyFrame KeyTime="0:0:1" Value="0"/>

</DoubleAnimationUsingKeyFrames>

</Storyboard>

</UserControl.Resources>

然后我们在第一个动画的Complete事件中切换控件,并开始第二个动画,如

 

void Storyboard_GoToDetails_Completed(object sender, EventArgs e)
{
FundDetails fd
= new FundDetails();
SVMain.Content
=fd;
this.Storyboard_GoToDetails_Second.Begin();
}

然后我们在行情控件里点击基金名称时通过委托或MainPage的引用启动第一个动画,我们的效果就实现了,很简单吧!

 

再看看我们第二个动画的效果,即在详情页面时通过点击导航上的行情按钮返回基金行情页面,如

 

一个类似3D翻转的效果,这个效果我们分析一下,其实也不很难,主要是控制好角度与位置,但显然的,一个容器满足不了要求了,因为我们会有两个控件同时存在的情况。那我们就要修改一下MainPage中的布局,如

 

具体实现的效果,网上有网友发布了一个封装好的类cShow3DPlane,可以拿来直接用,调用代码如

 

private cShow3DPlane c3d = new cShow3DPlane();



if (c3d.MoveOver())

{

c3d.SetInOutPlane(
this.gridS1, this.gridS2, enumDirection.Right);

c3d.Begin();

}

这块有一点要注意一下,默认情况下,当一个动画结束后,它会保留它最终的状态,因此,当我们做切换的时候,要注意两个grid的状态,在我们这个实现中,为了保留第一个动作的效果(因为两个动画是不同的实现,第一个动画是用同一个容器实现的),我需要记录下当前是哪一个grid正在被显示,而且如果当前已经是在行情界面的话,再点击行情导航按钮应该就不需要再有动作了,最终代码如下

 

View Code
private Grid currentGrid;//当前控件窗口,用以动画切换

private void LoadFundQuotes(Grid grids)
{
//加载基金行情

FundQuotes fq
= new FundQuotes();

fq.mp
= this;

grids.Children.Clear();

grids.Children.Add(fq);

}



private void HyperlinkButton_Click(object sender, System.Windows.RoutedEventArgs e)

{

if (currentGrid.Children.Count > 0 && currentGrid.Children[0] as FundQuotes == null)

{
//如果当前显示模块不是基金行情

if (currentGrid == this.gridS1)

{

LoadFundQuotes(
this.gridS2);

if (c3d.MoveOver())

{

c3d.SetInOutPlane(
this.gridS2, this.gridS1, enumDirection.Right);

c3d.Begin();

currentGrid
= this.gridS2;

}

}

else if (currentGrid == this.gridS2)

{

LoadFundQuotes(
this.gridS1);

if (c3d.MoveOver())

{

c3d.SetInOutPlane(
this.gridS1, this.gridS2, enumDirection.Right);

c3d.Begin();

currentGrid
= this.gridS1;

}

}

}

}

因为布局发生了变化,因此第一个动画的实现也要做相应的修改,最终代码如

 

void Storyboard_GoToDetails_Completed(object sender, EventArgs e)

{

FundDetails fd
= new FundDetails();

fd.currentFund
= this.gridS1.Tag as WcfService.FundQuotes;

currentGrid.Children.Clear();

currentGrid.Children.Add(fd);

this.Storyboard_GoToDetails_Second.Begin();

}

fd.currentFund = this.gridS1.Tag as WcfService.FundQuotes;这一句我是用来向详情界面传参用的,与动画本身无关。

原文地址:https://www.cnblogs.com/meteortent/p/2088175.html