dongxiaoling1029

导航

【转】Silverlight用代码实现对任意控件向4个方向进行3D旋转

最近在做一个SilverLight项目,两个屏幕面板切换(比如从一个Grid切换到另一个Grid)时需要用到3D旋转的方式,部分文字、按钮切换时也要用到3D旋转的方式,刚开始看到这样需求的时候,自然而然的想到了用storyboard来做动画,于是开始动起手来画,研究了一阵3D旋转的方式,画出了第一个面板的3D左切换方式,但随之而来的问题让人头疼,不光有右、上、下的不同甚至随机的切换方式,还有不同控件、动画速度等需要控制,用动画的方式做出来似乎程序的伸缩很小,也不是太方便,于是有了写一个实现这样功能的类来用的想法,日后如果碰到需要这类功能的需要还可以重复使用。

  用了一天来写代码并测试,感觉还算可以,写代码时用了几种Timer来尝试控制动画,包括使用Thread,发现还是用storyboard来做Timer比较合适,没有过多的限制和线程外控件等问题,所以类中的动画主要用了两个storyboard来做Timer,分别控控制一进一出,实现动画则用PlaneProjection类来控制。3D旋转的主要实现方法是对PlaneProjection类的LocalOffsetZ和GlobalOffsetZ属性值进行正确的设置,左右旋转时LocalOffsetZ设置为控件的Widh/2,上下旋转则为Height/2,GlobalOffsetZ设置为相应的负值,也就是GlobalOffsetZ=-LocalOffsetZ,如果不写这句,控件会被拉伸大一截,要加上这一句花了我好长时间在HELP看了老半天,其次就是RotationX和RotationY的角度设置问题,弄清楚后就基本可以写完成了。

 

  下面是类代码,大家可以把类引用到工程里或者是编译成DLL引用,后面还写了一个基本的应用例子:

应用图例:

 

 

 

-----------------类代码(c3dplane.cs)------------------------------------------------ 

c3dplane.cs代码
/* * 大家共同交流,共同进步 * QQ:16277488 * MAIL:fanxiaokaitp@163.com * * */using System;using System.Net;using System.Windows;using System.Windows.Controls;using System.Windows.Documents;using System.Windows.Ink;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Animation;using System.Windows.Shapes;namespace c3dplane{ public enum enumDirection { Up, Down, Left, Right }; public class cShow3DPlane { public cShow3DPlane() { m_IsMoveOverIn = true; m_IsMoveOverOut = true; m_MoveSpeed = 2; sbTimeIn = new Storyboard(); sbTimeOut = new Storyboard(); SetTime(10, 10); sbTimeIn.Completed += new EventHandler(sbTimeIn_Completed); sbTimeOut.Completed += new EventHandler(sbTimeOut_Completed); } private int m_TimeSpeed1, m_TimeSpeed2,m_MoveSpeed,m_PlaneSpeed,m_InEnd,m_OutEnd; private double m_InLocalZ,m_OutLocalZ; private PlaneProjection m_pInPlane,m_pOutPlane; private Storyboard sbTimeIn, sbTimeOut; private enumDirection m_Direction; private bool m_IsMoveOverIn,m_IsMoveOverOut; //根据方向初始化两个planeProjection的相关值 private void InitPlaneData() { m_pInPlane.RotationX = 0; m_pInPlane.RotationY = 0; m_pInPlane.RotationZ = 0; m_pInPlane.CenterOfRotationX = 0.5; m_pInPlane.CenterOfRotationY = 0.5; m_pInPlane.CenterOfRotationZ = 0; m_pOutPlane.RotationX = 0; m_pOutPlane.RotationY = 0; m_pOutPlane.RotationZ = 0; m_pOutPlane.CenterOfRotationX = 0.5; m_pOutPlane.CenterOfRotationY = 0.5; m_pOutPlane.CenterOfRotationZ = 0; m_pOutPlane.LocalOffsetZ = m_OutLocalZ; m_pOutPlane.GlobalOffsetZ = -m_OutLocalZ; m_pInPlane.LocalOffsetZ = m_InLocalZ; m_pInPlane.GlobalOffsetZ = -m_InLocalZ; switch (m_Direction) { case enumDirection.Up: m_pInPlane.RotationX = -90; m_InEnd = 0; m_pOutPlane.RotationX = 0; m_OutEnd = 90; m_PlaneSpeed = m_MoveSpeed; break; case enumDirection.Down: m_pInPlane.RotationX = 90; m_InEnd = 0; m_pOutPlane.RotationX = 0; m_OutEnd = -90; m_PlaneSpeed = -m_MoveSpeed; break; case enumDirection.Left: m_pInPlane.RotationY = 90; m_InEnd = 0; m_pOutPlane.RotationY = 0; m_OutEnd = -90; m_PlaneSpeed = -m_MoveSpeed; break; case enumDirection.Right: m_pInPlane.RotationY = -90; m_InEnd = 0; m_pOutPlane.RotationY = 0; m_OutEnd = 90; m_PlaneSpeed = m_MoveSpeed; break; } } public void Begin() { m_IsMoveOverIn = false; m_IsMoveOverOut = false; sbTimeIn.Begin(); sbTimeOut.Begin(); } //设置进入和离开对象 public void SetInOutPlane(Grid gridIn, Grid gridOut, enumDirection eDirection) { m_pInPlane = new PlaneProjection(); m_pOutPlane = new PlaneProjection(); gridIn.Projection = m_pInPlane; gridOut.Projection = m_pOutPlane; if (eDirection == enumDirection.Left || eDirection == enumDirection.Right) { m_InLocalZ = gridIn.ActualWidth / 2; m_OutLocalZ = gridOut.ActualWidth / 2; } else { m_InLocalZ = gridIn.ActualHeight / 2; m_OutLocalZ = gridOut.ActualHeight / 2; } m_Direction = eDirection; InitPlaneData(); } //重载 public void SetInOutPlane(Control controlIn, Control controlOut, enumDirection eDirection) { m_pInPlane = new PlaneProjection(); m_pOutPlane = new PlaneProjection(); controlIn.Projection = m_pInPlane; controlOut.Projection = m_pOutPlane; if (eDirection == enumDirection.Left || eDirection == enumDirection.Right) { m_InLocalZ = controlIn.ActualWidth / 2; m_OutLocalZ = controlOut.ActualWidth / 2; } else { m_InLocalZ = controlIn.ActualHeight / 2; m_OutLocalZ = controlOut.ActualHeight / 2; } m_Direction = eDirection; InitPlaneData(); } public bool MoveOver() { if (!m_IsMoveOverIn || !m_IsMoveOverOut) return false; else return true; } //设置进入和离开动画的速度 public void SetTime(int timeSpeed1, int timeSpeed2) { m_TimeSpeed1 = timeSpeed1; m_TimeSpeed2 = timeSpeed2; sbTimeIn.Duration = new Duration(TimeSpan.FromMilliseconds(m_TimeSpeed1)); sbTimeOut.Duration = new Duration(TimeSpan.FromMilliseconds(m_TimeSpeed2)); } //离开对象的动画 void sbTimeOut_Completed(object sender, EventArgs e) { //throw new NotImplementedException(); if (m_Direction == enumDirection.Left || m_Direction == enumDirection.Right) { m_pOutPlane.RotationY += m_PlaneSpeed; if (m_pOutPlane.RotationY == m_OutEnd) m_IsMoveOverOut = true; } if (m_Direction == enumDirection.Up || m_Direction == enumDirection.Down) { m_pOutPlane.RotationX += m_PlaneSpeed; if (m_pOutPlane.RotationX == m_OutEnd) m_IsMoveOverOut = true; } if (!m_IsMoveOverOut) sbTimeOut.Begin(); else { m_pOutPlane.LocalOffsetZ = 0; m_pOutPlane.GlobalOffsetZ = 0; } } //进入对象的动画 void sbTimeIn_Completed(object sender, EventArgs e) { //throw new NotImplementedException(); if (m_Direction == enumDirection.Left || m_Direction == enumDirection.Right) { m_pInPlane.RotationY += m_PlaneSpeed; if (m_pInPlane.RotationY == m_InEnd) m_IsMoveOverIn = true; } if (m_Direction == enumDirection.Up || m_Direction == enumDirection.Down) { m_pInPlane.RotationX += m_PlaneSpeed; if (m_pInPlane.RotationX == m_InEnd) m_IsMoveOverIn = true; } if (!m_IsMoveOverIn) sbTimeIn.Begin(); else { m_pInPlane.LocalOffsetZ = 0; m_pInPlane.GlobalOffsetZ = 0; } } }}

 

 

 

下面是应用例子:

 

-----------------(MainPage.xaml)------------------------------------------------

 

MainPage.xaml代码
<UserControl x:Class="_3dPlaneTest.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="480" d:DesignWidth="640"> <Grid x:Name="LayoutRoot" Background="White" ShowGridLines="True"> <Grid.RowDefinitions> <RowDefinition ></RowDefinition> <RowDefinition ></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <Grid Grid.Row="0" Grid.Column="0"> <Button x:Name="btnUp" Content="上" VerticalAlignment="Top" HorizontalAlignment="Center" Width="200" Margin="20" Click="btnUp_Click"></Button> <Button x:Name="btnDown" Content="下" VerticalAlignment="Bottom" HorizontalAlignment="Center" Width="200" Margin="20" Click="btnDown_Click"></Button> <Button x:Name="btnLeft" Content="左" VerticalAlignment="Center" HorizontalAlignment="Left" Height="200" Margin="20" Click="btnLeft_Click"></Button> <Button x:Name="btnRight" Content="右" VerticalAlignment="Center" HorizontalAlignment="Right" Height="200" Margin="20" Click="btnRight_Click"></Button> <Grid x:Name="gridUp" Background="Red" Width="200" Height="100"> <TextBlock Text="这是上喔" Foreground="White" VerticalAlignment="Top" HorizontalAlignment="Center"/> </Grid> <Grid x:Name="gridDown" Background="Green" Width="200" Height="100"> <TextBlock Text="这是下喔" Foreground="White" VerticalAlignment="Bottom" HorizontalAlignment="Center"/> </Grid> <Grid x:Name="gridLeft" Background="Blue" Width="200" Height="100"> <TextBlock Text="这是左喔" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Left"/> </Grid> <Grid x:Name="gridRight" Background="Cornsilk" Width="200" Height="100"> <TextBlock Text="这是右喔" Foreground="Red" VerticalAlignment="Center" HorizontalAlignment="Right"/> </Grid> </Grid> <Grid Grid.Row="0" Grid.Column="1"> <Grid.RowDefinitions> <RowDefinition ></RowDefinition> <RowDefinition ></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <Button x:Name="btnTest1" Content="QQ:16277488,返回了" Width="220" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center" Click="btnTest1_Click"></Button> <Button x:Name="btnTest2" Content="这是测试控件旋转" Width="220" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center" Click="btnTest2_Click"></Button> <Button x:Name="btnTest3" Content="mail:fanxiaokaitp@163.com,返回了" Grid.Row="1" Width="220" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center" Click="btnTest3_Click"></Button> <Button x:Name="btnTest4" Content="这也是测试控件旋转" Grid.Row="1" Width="220" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center" Click="btnTest4_Click"></Button> </Grid> </Grid></UserControl>

-----------------(MainPage.xaml.cs)------------------------------------------------

using System;using System.Collections.Generic;using System.Linq;using System.Net;using System.Windows;using System.Windows.Controls;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Animation;using System.Windows.Shapes;using c3dplane;namespace _3dPlaneTest{ public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); PlaneProjection pp = new PlaneProjection(); pp.RotationY = 90; gridUp.Projection = pp; gridDown.Projection = pp; gridLeft.Projection = pp; gridCur = gridRight; } private cShow3DPlane c3d=new cShow3DPlane(); private Grid gridCur=new Grid(); private void btnUp_Click(object sender, RoutedEventArgs e) { if (gridCur ==gridUp ) { MessageBox.Show("现在已经是 上 了"); return; } if (c3d.MoveOver()) { c3d.SetInOutPlane(gridUp, gridCur, enumDirection.Up); gridCur = gridUp; c3d.Begin(); } } private void btnRight_Click(object sender, RoutedEventArgs e) { if (gridCur == gridRight) { MessageBox.Show("现在已经是 右 了"); return; } if (c3d.MoveOver()) { c3d.SetInOutPlane(gridRight, gridCur, enumDirection.Right); gridCur = gridRight; c3d.Begin(); } } private void btnLeft_Click(object sender, RoutedEventArgs e) { if (gridCur == gridLeft) { MessageBox.Show("现在已经是 左 了"); return; } if (c3d.MoveOver()) { c3d.SetInOutPlane(gridLeft, gridCur, enumDirection.Left); gridCur = gridLeft; c3d.Begin(); } } private void btnDown_Click(object sender, RoutedEventArgs e) { if (gridCur == gridDown) { MessageBox.Show("现在已经是 下 了"); return; } if (c3d.MoveOver()) { c3d.SetInOutPlane(gridDown, gridCur, enumDirection.Down); gridCur = gridDown; c3d.Begin(); } } private void btnTest2_Click(object sender, RoutedEventArgs e) { if (c3d.MoveOver()) { c3d.SetInOutPlane(btnTest1, btnTest2, enumDirection.Left); c3d.Begin(); } } private void btnTest1_Click(object sender, RoutedEventArgs e) { if (c3d.MoveOver()) { c3d.SetInOutPlane(btnTest2, btnTest1, enumDirection.Right); c3d.Begin(); } } private void btnTest3_Click(object sender, RoutedEventArgs e) { if (c3d.MoveOver()) { c3d.SetInOutPlane(btnTest4, btnTest3, enumDirection.Up); c3d.Begin(); } } private void btnTest4_Click(object sender, RoutedEventArgs e) { if (c3d.MoveOver()) { c3d.SetInOutPlane(btnTest3, btnTest4, enumDirection.Down); c3d.Begin(); } } }}

 

posted on 2010-10-24 21:34  dongxiaoling1029  阅读(719)  评论(1编辑  收藏  举报