zoukankan      html  css  js  c++  java
  • SilverLight用代码实现对任意控件向4个方向进行3D旋转的类

    转载地址:http://www.cnblogs.com/fanxiaokaitp/archive/2010/05/21/1740532.html

    最近在做一个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的角度设置问题,弄清楚后就基本可以写完成了。

          找到了个可以上传XAP在线演示的地方,大家可以先看看在线演示,地址: http://www.bbniu.com/matrix/ShowApplication.aspx?id=122

      下面是类代码,大家可以把类引用到工程里或者是编译成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)------------------------------------------------

    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();
    }
    }


    }
    }

    以上是类和应用代码。

  • 相关阅读:
    大神语录1 如何滑动fragmentmanager里面一个fragment里面的viewgroup---dispatchTouchEvent 、onInterceptTouchEvent 、onTouchEvent
    转载-好的简历
    安卓开发8- 安卓开源项目整理github
    安卓开发7-网络通信-如何使用webservice
    安卓开发6 -Viewpager+fragment更新数据
    leetcode rotatenumber
    Java程序执行时间的简单方法
    LeetCode happyint
    安卓开发5-fragment和activity
    [转]深入理解AsyncTask的工作原理
  • 原文地址:https://www.cnblogs.com/jiewei915/p/1777393.html
Copyright © 2011-2022 走看看