《Windows Fun 7》 二:Windows Phone怎样实现一个水平切换Page的Transition
2011-09-10 19:39
597 查看
前言
重置过WindowsPhone7手机的朋友,一定记得,重置之后第一件要做的事是设置语言,时区,时间,LiveID等信息。我们也一定记得那是一种水平切换的动画。当我们点击下一步时,页面从右向左滑动。有点类似iphone主页菜单的左右滑动效果。
前段时间QQ群有人在问这种效果。这样的效果有时候会用到,比如街旁WP7客户端开始的引导用户使用的几个页面,类似教程,就可以做成这种效果。还有,如果需要在客户端注册,也可以把几个注册过程做成这样的效果,还有比如翻书的效果,也可以这样平移……
我们可以看下一下效果,它是从右向左连贯的水平滑动,本篇就分析这样的思路以及实现原理,并给出源代码下载:
1.你的思路
如果我猜的没错,你已经有了大概的思路:设置一个Canvas,按每个页面实际的位置布局,然后每次修改每个元素的Canvas.Left……
确实,以前我也这么干过!
这样虽然可行,但是有点显得我们不够专业,而且所有页面需要一次实例化,如果页面过多,那会影响第一次加载时间。
那怎么办呢?不急,我们一步一步来慢慢分析。
2.Silverlight中的简单导航
切换,切换,切换,该怎么切换呢?
想想,在Silverlight中,我们要由一个UI页面切换到另一个UI页面,在不借助Frame的时候,会怎么办呢。
最简单的,就是将容器的Content给替换成另一个对象,没错就是这样。
所以,页面切换的最简单模型就是,最外层放置一个ContentControl,第一次显示的时候给他的Content赋值一个页面实例,在用户点击导航按钮之后,用另一个页面实例替换。如下的模型:
3.Frame+Page
其实,没错啦,页面切换的基本模型就是这么简单。
Silverlight提供了一个Frame+Page的导航模型,它其实仍然是这样的原理。我们首先看下Frame的定义:
[code]{
[/code]
Frame首先是一个ContentControl,那么每个Page就是一个页面了。不同的是不需要我们去替换Content,我们只需要指定一个XAML文件的地址,Frame会根据路径找到这个页面,然后实例化,然后自己替换它的Content。
相比我们前面得出的最简单的模型,它仅仅是提供了一些导航事件,使得我们可以做出一些处理。
我们看到,Frame模型简化了我们开发中的页面导航。还是很有用的。
4.WindowsPhone7中的Transitions
Nice!但是页面切换太突兀了,一下子就换过来,一点都不符合Silverlight的风格,Silverlight可是做动画的啊,Silverlight可是替换Flash的啊,为什么要像HTML一样导航呢。
WindowsPhone7操作系统出来后,Metro横空出世,Metro强调流畅,强调平滑,强调每户的每个操作和响应都能通过一些视觉变换反馈给用户。因此,给Page之间的过度加入了Transition。
不过默认的PhoneApplicationFrame并没有加入Transition的功能,我们需要去分析Toolkit里面的TransitionFrame代码。
对TransitionFrame的分析以及将本实例转化为Frame的方式将会在下一篇分析。
5.本示例代码分析
本实例实际上来源于PDC大会上介绍ExpressionBlend4时官方演示的源代码示例。其中我把导航的部分抽取出来。
和Frame+Page的模型类似,本实例也由两部分组成:TransitionContentControl和SlideShow。其中TransitionContentControl类似于Frame的功能,而SlideShow类似于Page,不同的是SlideShow是继承于ItemsControl,它首先就会取得所有页面并实例化,这在页面多得时候不是很可取,后面我会将它进行改造。
[code]{
[/code]
和前面的Frame没有太大区别,神奇之处在于多了一个TransitionStyle依赖属性,这个Style也没什么区别,神奇之处在于多了一个LayoutStates
[code]<SetterProperty="Template">
[/code]
关于LayoutStates,我之前的一篇文章有介绍:/article/5119112.html
其实也很简单,它定义了三个状态BeforeLoaded,AfterLoaded,BeforeUnloaded。
BeforeLoaded就是一个页面加载之前的状态,如果页面是从右向左滑动,那么它应该是在屏幕右边看不见:
[code]<Storyboard>
[/code]
我们看到这个状态,其CompositeTransform.TranslateX被设置到屏幕后边的位置,并且透明度为0,不可见。
与BeforeLoaded状态相反,BeforeUnloaded如下:
[code]<Storyboard>
[/code]
[code]<CompositeTransform/>
[/code]
好了,由此我们不难明白,由BeforeLoaded状态过度到AfterLoaded状态,就是新页面由右向左滑入的动画;而由AfterLoaded状态过度到BeforeUnloaded状态,就实现了页面向左淡出的动画效果。
那么你会问,这两个状态过度如何同时进行的。实际上,这两个动画不是同时作用在一个元素上,通过前面简单的模型,我们知道Frame实际上控制着两个页面实例,在切换的时候,它将两个不同的状态过度分别作用的两个页面上,具体的代码在OnContentChanged方法中:
[code]{
[/code]
6.下一篇内容
在此基础上,我相信你已经大概知道TransitionFrame的实现思路了,是的,至少思想是类似的。
但是TransitionFrame要复杂得多,我将在下一篇分析。
本实例实际上有很多缺陷:
所有页面第一次全部实例化,不能像Frame可以在导航的时候加载页面
不能结合PhoneApplicationPage响应回退键,需要响应后退事件还需要手工做一些事情
后续,我将把次功能整合进TransitionFrame或者自定义一个Frame,那是就会分析一下Frame,这样就可以把这种效果与Back事件集成。
7.源代码下载
源代码:http://files.cnblogs.com/hielvis/TecHappy.WindowsPhone.Toolkit.rar
Xap包:http://files.cnblogs.com/hielvis/TecHappy.WindowsPhone.Sample.xap
8.WindowsPhone7技术沙龙
9月17号,我们将在微软亚太研发集团举办WindowsPhone7的技术沙龙,将有一些大家熟悉的一线开发人员分享实战经验。
微博报名:http://event.weibo.com/199979
我们官方宣传页:http://www.techappy.net/
特邀嘉宾
重置过WindowsPhone7手机的朋友,一定记得,重置之后第一件要做的事是设置语言,时区,时间,LiveID等信息。我们也一定记得那是一种水平切换的动画。当我们点击下一步时,页面从右向左滑动。有点类似iphone主页菜单的左右滑动效果。
前段时间QQ群有人在问这种效果。这样的效果有时候会用到,比如街旁WP7客户端开始的引导用户使用的几个页面,类似教程,就可以做成这种效果。还有,如果需要在客户端注册,也可以把几个注册过程做成这样的效果,还有比如翻书的效果,也可以这样平移……
我们可以看下一下效果,它是从右向左连贯的水平滑动,本篇就分析这样的思路以及实现原理,并给出源代码下载:
1.你的思路
如果我猜的没错,你已经有了大概的思路:设置一个Canvas,按每个页面实际的位置布局,然后每次修改每个元素的Canvas.Left……
确实,以前我也这么干过!
这样虽然可行,但是有点显得我们不够专业,而且所有页面需要一次实例化,如果页面过多,那会影响第一次加载时间。
那怎么办呢?不急,我们一步一步来慢慢分析。
2.Silverlight中的简单导航
切换,切换,切换,该怎么切换呢?
想想,在Silverlight中,我们要由一个UI页面切换到另一个UI页面,在不借助Frame的时候,会怎么办呢。
最简单的,就是将容器的Content给替换成另一个对象,没错就是这样。
所以,页面切换的最简单模型就是,最外层放置一个ContentControl,第一次显示的时候给他的Content赋值一个页面实例,在用户点击导航按钮之后,用另一个页面实例替换。如下的模型:
3.Frame+Page
其实,没错啦,页面切换的基本模型就是这么简单。
Silverlight提供了一个Frame+Page的导航模型,它其实仍然是这样的原理。我们首先看下Frame的定义:
publicclassFrame:ContentControl,INavigate
[code]{
publicboolCanGoBack{get;internalset;}
publicboolCanGoForward{get;internalset;}
publicUriCurrentSource{get;internalset;}
publicUriSource{get;set;}
publicUriMapperBaseUriMapper{get;set;}
publiceventFragmentNavigationEventHandlerFragmentNavigation;
publiceventNavigatedEventHandlerNavigated;
publiceventNavigatingCancelEventHandlerNavigating;
publiceventNavigationFailedEventHandlerNavigationFailed;
publiceventNavigationStoppedEventHandlerNavigationStopped;
publicvoidGoBack();
publicvoidGoForward();
publicboolNavigate(Urisource);
publicvoidStopLoading();
}
[/code]
Frame首先是一个ContentControl,那么每个Page就是一个页面了。不同的是不需要我们去替换Content,我们只需要指定一个XAML文件的地址,Frame会根据路径找到这个页面,然后实例化,然后自己替换它的Content。
相比我们前面得出的最简单的模型,它仅仅是提供了一些导航事件,使得我们可以做出一些处理。
我们看到,Frame模型简化了我们开发中的页面导航。还是很有用的。
4.WindowsPhone7中的Transitions
Nice!但是页面切换太突兀了,一下子就换过来,一点都不符合Silverlight的风格,Silverlight可是做动画的啊,Silverlight可是替换Flash的啊,为什么要像HTML一样导航呢。
WindowsPhone7操作系统出来后,Metro横空出世,Metro强调流畅,强调平滑,强调每户的每个操作和响应都能通过一些视觉变换反馈给用户。因此,给Page之间的过度加入了Transition。
不过默认的PhoneApplicationFrame并没有加入Transition的功能,我们需要去分析Toolkit里面的TransitionFrame代码。
对TransitionFrame的分析以及将本实例转化为Frame的方式将会在下一篇分析。
5.本示例代码分析
本实例实际上来源于PDC大会上介绍ExpressionBlend4时官方演示的源代码示例。其中我把导航的部分抽取出来。
和Frame+Page的模型类似,本实例也由两部分组成:TransitionContentControl和SlideShow。其中TransitionContentControl类似于Frame的功能,而SlideShow类似于Page,不同的是SlideShow是继承于ItemsControl,它首先就会取得所有页面并实例化,这在页面多得时候不是很可取,后面我会将它进行改造。
publicclassTransitionContentControl:Control
[code]{
privateContentControlcurrentWrappedContent=null;
privateGridgrid=null;
publicStyleTransitionStyle{get;set;}
publicobjectContent{get;set;}
staticvoidContentPropertyChanged(objecto,DependencyPropertyChangedEventArgsargs);
staticvoidTransitionStylePropertyChanged(objecto,DependencyPropertyChangedEventArgsargs);}
[/code]
和前面的Frame没有太大区别,神奇之处在于多了一个TransitionStyle依赖属性,这个Style也没什么区别,神奇之处在于多了一个LayoutStates
<Stylex:Key="SlideTemplate"TargetType="ContentControl">
[code]<SetterProperty="Template">
<Setter.Value>
<ControlTemplateTargetType="ContentControl">
<Gridx:Name="grid"Background="{TemplateBindingBackground}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroupx:Name="LayoutStates">
<VisualStatex:Name="BeforeLoaded">
<VisualStatex:Name="AfterLoaded"/>
<VisualStatex:Name="BeforeUnloaded">
</VisualStateManager.VisualStateGroups>
<Grid.RenderTransform>
<CompositeTransform/>
</Grid.RenderTransform>
<ContentPresenterx:Name="contentPresenter"ContentTemplate="{TemplateBindingContentTemplate}"Content="{TemplateBindingContent}"}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
[/code]
关于LayoutStates,我之前的一篇文章有介绍:
其实也很简单,它定义了三个状态BeforeLoaded,AfterLoaded,BeforeUnloaded。
BeforeLoaded就是一个页面加载之前的状态,如果页面是从右向左滑动,那么它应该是在屏幕右边看不见:
<VisualStatex:Name="BeforeLoaded">
[code]<Storyboard>
<DoubleAnimationDuration="0"To="1000"
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)"
Storyboard.TargetName="grid"/>
<DoubleAnimationDuration="0"To="0"
Storyboard.TargetProperty="(UIElement.Opacity)"
Storyboard.TargetName="grid"/>
</Storyboard>
</VisualState>
[/code]
我们看到这个状态,其CompositeTransform.TranslateX被设置到屏幕后边的位置,并且透明度为0,不可见。
与BeforeLoaded状态相反,BeforeUnloaded如下:
<VisualStatex:Name="BeforeUnloaded">
[code]<Storyboard>
<DoubleAnimationDuration="0"To="-1000"
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)"
Storyboard.TargetName="grid"/>
<DoubleAnimationDuration="0"To="0"
Storyboard.TargetProperty="(UIElement.Opacity)"
Storyboard.TargetName="grid"/>
</Storyboard>
</VisualState>
而AfterLoaded就是一个页面正常显示的状态,那为什么它是空的没有设置呢,那是因为它和正常状态一样,没有修改任何元位置,下面就是正常状态:
[/code]
<Grid.RenderTransform>
[code]<CompositeTransform/>
</Grid.RenderTransform>
[/code]
好了,由此我们不难明白,由BeforeLoaded状态过度到AfterLoaded状态,就是新页面由右向左滑入的动画;而由AfterLoaded状态过度到BeforeUnloaded状态,就实现了页面向左淡出的动画效果。
那么你会问,这两个状态过度如何同时进行的。实际上,这两个动画不是同时作用在一个元素上,通过前面简单的模型,我们知道Frame实际上控制着两个页面实例,在切换的时候,它将两个不同的状态过度分别作用的两个页面上,具体的代码在OnContentChanged方法中:
protectedvirtualvoidOnContentChanged(objectoldContent,objectnewContent)
[code]{
ContentControloldWrapper=this.currentWrappedContent;if(oldWrapper!=null)
{
VisualStateGrouplayoutStatesGroup=FindNameInWrapper(oldWrapper,"LayoutStates")asVisualStateGroup;
if(layoutStatesGroup==null)
{
this.grid.Children.Remove(oldWrapper);
SetContent(oldWrapper,null);
}
else
{
layoutStatesGroup.CurrentStateChanged+=delegate(objectsender,VisualStateChangedEventArgsargs)
{
this.grid.Children.Remove(oldWrapper);
SetContent(oldWrapper,null);
};
VisualStateManager.GoToState(oldWrapper,this.Reversed?"BeforeLoaded":"BeforeUnloaded",true);
}
}
ContentControlnewWrapper=newContentControl();
newWrapper.Style=this.TransitionStyle;
newWrapper.HorizontalContentAlignment=HorizontalAlignment.Stretch;
newWrapper.VerticalContentAlignment=VerticalAlignment.Stretch;
this.grid.Children.Add(newWrapper);
newWrapper.ApplyTemplate();
if(this.TransitionStyle!=null)
{
SetContent(newWrapper,newContent);
if(oldWrapper!=null)
{
VisualStateManager.GoToState(newWrapper,this.Reversed?"BeforeUnloaded":"BeforeLoaded",false);
VisualStateManager.GoToState(newWrapper,"AfterLoaded",true);
}
}
this.currentWrappedContent=newWrapper;}
这个方法实际上是本示例最核心的部分,它分别将两种状态切换作用在两个页面实例上,然后两个动画同时作用,就形成了页面由右向左滑入的效果。
这里也提前指出TransitionFrame的一个缺点,它不能像这样两个动画同时作用。我后面将要改造的Frame会加上LayoutStates的支持。
此示例其实代码非常精简,思路也很清晰。以上我分析了核心部分。
[/code]
6.下一篇内容
在此基础上,我相信你已经大概知道TransitionFrame的实现思路了,是的,至少思想是类似的。
但是TransitionFrame要复杂得多,我将在下一篇分析。
本实例实际上有很多缺陷:
所有页面第一次全部实例化,不能像Frame可以在导航的时候加载页面
不能结合PhoneApplicationPage响应回退键,需要响应后退事件还需要手工做一些事情
后续,我将把次功能整合进TransitionFrame或者自定义一个Frame,那是就会分析一下Frame,这样就可以把这种效果与Back事件集成。
7.源代码下载
源代码:
Xap包:
8.WindowsPhone7技术沙龙
9月17号,我们将在微软亚太研发集团举办WindowsPhone7的技术沙龙,将有一些大家熟悉的一线开发人员分享实战经验。
微博报名:
我们官方宣传页:
特邀嘉宾
相关文章推荐
- 《Windows Fun 7》 二:Windows Phone怎样实现一个水平切换Page的Transition
- 一个简单的底部Tab切换实现
- Jquery实现一个图片滚动切换
- android中很多情况下我们需要会使用多个fragment,我们这时就需要一个showFragment来实现fragment之间的切换
- Activity切换时动画(animate)效果实现(overridePendingTransition)
- jsp页面怎样实现重新打开一个新的页面
- 利用面向对象的思想实现主从线程下多次循环的切换(因为他们要同步,所以他们是有关联的,所以把它们放在一个类里)
- 同一个shell下实现多个composite的切换
- Tab切换动画滑动效果的一个简单实现
- 【Android2D游戏开发十六】(上文之触摸屏手势)详解Android Gesture 手势操作!利用手势实现一个简单切换图片的功能!
- Qt 切换皮肤的一个实现思路
- 怎样用笔记本的无线网卡做一个AP 实现笔记本做wifi热点供手机、平板电脑wifi上网而不用无线路由器
- b803 用java怎样实现遍历一个字符串的每一个字母
- 怎样实现一个图层的运动(可实现贪吃蛇小游戏,代码现不完善,请关注本人,今日完善)
- 怎样实现一个程序是APP+APPWIDGET
- Android 实现个性的ViewPager切换动画 实战PageTransformer(兼容Android3.0以下)
- Android 一个Activity 里面放置多个 Fragment 实现点击切换的Tab 页面效果
- 【Android游戏开发十六】Android Gesture之【触摸屏手势识别】操作!利用触摸屏手势实现一个简单切换图片的功能!
- 父元素为一个div,宽度高度不固定,子元素是一个块状元素,宽高已知,如何实现子元素在父元素内水平、垂直居中?
- 怎样在vs2010里面实现两个编辑控件对应一个消息处理函数