none
如果实现动画在指定时间点中止,并反转。 RRS feed

答案

  • xaml

    Code Snippet



    <UserControl x:Class="StoryBoardDemo.Page"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Width="400" Height="300">
        <Canvas x:Name="LayoutRoot" Background="White" Loaded="LayoutRoot_Loaded">
            <Rectangle x:Name="obj0" Width="50" Height="50" Fill="Red"/>
            <StackPanel Canvas.Top="60">
                <Button x:Name="btn0" Content="暂停并返回" Click="btn0_Click"></Button>
            </StackPanel>
        </Canvas>
    </UserControl>

     

    cs

     

    Code Snippet

    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 System.Threading;
    using System.Windows.Threading;

    namespace StoryBoardDemo
    {
        public partial class Page : UserControl
        {
            public Page()
            {
                InitializeComponent();
            }

            private void btn0_Click(object sender, RoutedEventArgs e)
            {
                long ltick = sb.GetCurrentTime().Ticks;
                sb.Stop();
                lt1 = 0;
                lt2 = ltick;
                dv1 = ltick * speed;
                dv2 = 0;
                k1.KeyTime = new TimeSpan(lt1);
                k1.Value = dv1;
                k2.KeyTime = new TimeSpan(lt2);
                k2.Value = dv2;
                sb.Begin();
            }
            Storyboard sb;
            DoubleAnimationUsingKeyFrames dak;
            SplineDoubleKeyFrame k1, k2;
            double dv1, dv2;
            long lt1, lt2;
            double speed;
            private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
            {
                sb = new Storyboard();
                dak = new DoubleAnimationUsingKeyFrames();
                sb.Children.Add(dak);
                lt1 = 0;
                lt2 = 40000000;

                speed = 0.00001;
                dv1 = 0;
                dv2 = lt2 * speed;

                k1 = new SplineDoubleKeyFrame();
                k2 = new SplineDoubleKeyFrame();

                k1.KeyTime = new TimeSpan(lt1);
                k1.Value = dv1;
                k2.KeyTime = new TimeSpan(lt2);
                k2.Value = dv2;

                dak.KeyFrames.Add(k1);
                dak.KeyFrames.Add(k2);

                Storyboard.SetTarget(dak, obj0);
                Storyboard.SetTargetProperty(dak, new PropertyPath("(Canvas.Left)"));

                sb.Begin();
            }


        }
    }

     

     

    要想实现自己的逻辑就要写程序了,也不难,只要定义了speed速度,把原路径记忆好了,重新绘制StoryBoard就可以了,如果经常使用,可以把这个方法自己封装个类,到时候只要传入GetCurrentTime().Ticks跟 StoryBoard就可以实现任意点的反播了,当然就不是两个KeyFrame,取 KeyFrames可以得到集合,剩下就自己完善啦

    当然你要定义了加速度的话,可能会更复杂一点,无非也就是点数学换算公式啦

    2008年11月12日 16:15
    版主

全部回复

  • 根据我的理解,反转的部分实现很容易。

     

    计时器应该有对应的类实现啊,到点出发反转的动画就可以了

    2008年11月11日 11:41
  • 可以在动画文件中的时间点指定 时间轴节点 然后注册 MarkerReached 事件,当处发事件时就是你要中止的时间(个人认为这种方法要比读Position效率高),然后调用Stop方法就可以中止,并可以通过指定Postition的方式来反转动画.
    2008年11月11日 11:52
  • Code Snippet

     

    <UserControl
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     x:Class="MoveReview.Page"
     Width="640" Height="480">
     <UserControl.Resources>
      <Storyboard x:Name="Storyboard1" AutoReverse="True" RepeatBehavior="Forever" >
       <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
        <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
        <SplineDoubleKeyFrame KeyTime="00:00:01" Value="95"/>
       </DoubleAnimationUsingKeyFrames>
       <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">
        <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
        <SplineDoubleKeyFrame KeyTime="00:00:01" Value="-78"/>
       </DoubleAnimationUsingKeyFrames>
      </Storyboard>
     </UserControl.Resources>

     <Grid x:Name="LayoutRoot" Background="White">
      <Rectangle Height="64" HorizontalAlignment="Left" Margin="179,143,0,0" VerticalAlignment="Top" Width="82" Fill="#FFFFFFFF" Stroke="#FF000000" x:Name="rectangle" RenderTransformOrigin="0.5,0.5">
       <Rectangle.RenderTransform>
        <TransformGroup>
         <ScaleTransform/>
         <SkewTransform/>
         <RotateTransform/>
         <TranslateTransform/>
        </TransformGroup>
       </Rectangle.RenderTransform>
      </Rectangle>
     </Grid>
    </UserControl>

     

     

    主要用Storyboard的AutoReverse属性设置成为True,当到达结束时间时,动画会自动翻转

    RepeatBehavior属性设置成Forever时无限翻转


    2008年11月11日 14:46
    版主
  • 哈,看来我是理解错意思了  如果实现动画在指定时间点中止,并反转。这里 动画 是指自定义动画而不是要播放的影像呀:)
    2008年11月12日 0:12
  •  

    我的意思是假如动画总时长10秒,有可能在动画播放到3秒时需要动画停止并反转,也有可能在动画播放到5秒时需要反转。
    2008年11月12日 2:43
  • 你这里指的动画,是指Silverlight用XAML做的动画呀?还是指要播放的影像文件呀?

    2008年11月12日 3:20
  •  

    是Storyboard
    2008年11月12日 3:27
  • 给你写了个算法,不知道有没有更好的方法

     

    XAML

    <UserControl
        x:Class="SilverlightApplication1.Page"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    >
        <Grid x:Name="LayoutRoot" Background="White">
            <StackPanel
                Orientation="Vertical"
            >
                <Button
                    x:Name="butTest"
                    Margin="0,10,0,0"
                    Content="Test"
                    Width="100"
                    Height="25"
                />
                <Rectangle
                    x:Name="rectTest"
                    Margin="0,10,0,0"
              Width="0"
              Height="100"
              Fill="Blue"
             >
                    <Rectangle.Triggers>
                        <EventTrigger
                RoutedEvent="Rectangle.Loaded"
               >
                            <BeginStoryboard>
                                <Storyboard
                                    x:Name="storyboardTest"
                                >
                                    <DoubleAnimation
                                        x:Name="dblanimationTest"
                   Storyboard.TargetName="rectTest"
                   Storyboard.TargetProperty="Width"
                   From="100"
                   To="500"
                   Duration="0:0:10"
                  />
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger>
                    </Rectangle.Triggers>
                </Rectangle>
            </StackPanel>
           
        </Grid>
    </UserControl>

    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;

    namespace SilverlightApplication1
    {
        public partial class Page : UserControl
        {
            public Page()
            {
                InitializeComponent();
                InitObject();
            }

            private void InitObject()
            {
                butTest.Click += new RoutedEventHandler(butTest_Click);
            }

            void butTest_Click(object sender, RoutedEventArgs e)
            {
                storyboardTest.Stop();

                double dblSourceFrom = dblanimationTest.From.Value;

                System.TimeSpan timespanNow = storyboardTest.GetCurrentTime();

                double dblRate = System.Math.Abs(dblanimationTest.To.Value - dblanimationTest.From.Value) / dblanimationTest.Duration.TimeSpan.Ticks;

                double dblValue = (dblanimationTest.From.Value < dblanimationTest.To.Value ? dblRate * timespanNow.Ticks + dblanimationTest.From.Value : dblanimationTest.From.Value - dblRate * timespanNow.Ticks);

                dblanimationTest.From = dblValue;
                dblanimationTest.To = dblSourceFrom;
                dblanimationTest.Duration = timespanNow;

                storyboardTest.Begin();
            }

        }
    }

    2008年11月12日 6:34
  • xaml

    Code Snippet



    <UserControl x:Class="StoryBoardDemo.Page"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Width="400" Height="300">
        <Canvas x:Name="LayoutRoot" Background="White" Loaded="LayoutRoot_Loaded">
            <Rectangle x:Name="obj0" Width="50" Height="50" Fill="Red"/>
            <StackPanel Canvas.Top="60">
                <Button x:Name="btn0" Content="暂停并返回" Click="btn0_Click"></Button>
            </StackPanel>
        </Canvas>
    </UserControl>

     

    cs

     

    Code Snippet

    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 System.Threading;
    using System.Windows.Threading;

    namespace StoryBoardDemo
    {
        public partial class Page : UserControl
        {
            public Page()
            {
                InitializeComponent();
            }

            private void btn0_Click(object sender, RoutedEventArgs e)
            {
                long ltick = sb.GetCurrentTime().Ticks;
                sb.Stop();
                lt1 = 0;
                lt2 = ltick;
                dv1 = ltick * speed;
                dv2 = 0;
                k1.KeyTime = new TimeSpan(lt1);
                k1.Value = dv1;
                k2.KeyTime = new TimeSpan(lt2);
                k2.Value = dv2;
                sb.Begin();
            }
            Storyboard sb;
            DoubleAnimationUsingKeyFrames dak;
            SplineDoubleKeyFrame k1, k2;
            double dv1, dv2;
            long lt1, lt2;
            double speed;
            private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
            {
                sb = new Storyboard();
                dak = new DoubleAnimationUsingKeyFrames();
                sb.Children.Add(dak);
                lt1 = 0;
                lt2 = 40000000;

                speed = 0.00001;
                dv1 = 0;
                dv2 = lt2 * speed;

                k1 = new SplineDoubleKeyFrame();
                k2 = new SplineDoubleKeyFrame();

                k1.KeyTime = new TimeSpan(lt1);
                k1.Value = dv1;
                k2.KeyTime = new TimeSpan(lt2);
                k2.Value = dv2;

                dak.KeyFrames.Add(k1);
                dak.KeyFrames.Add(k2);

                Storyboard.SetTarget(dak, obj0);
                Storyboard.SetTargetProperty(dak, new PropertyPath("(Canvas.Left)"));

                sb.Begin();
            }


        }
    }

     

     

    要想实现自己的逻辑就要写程序了,也不难,只要定义了speed速度,把原路径记忆好了,重新绘制StoryBoard就可以了,如果经常使用,可以把这个方法自己封装个类,到时候只要传入GetCurrentTime().Ticks跟 StoryBoard就可以实现任意点的反播了,当然就不是两个KeyFrame,取 KeyFrames可以得到集合,剩下就自己完善啦

    当然你要定义了加速度的话,可能会更复杂一点,无非也就是点数学换算公式啦

    2008年11月12日 16:15
    版主
  • 再补充下.这只是一个值的翻转,要是多个Animation可以通过sb.Children取出来

    2008年11月12日 16:23
    版主
  • Hi

    2008年11月21日 2:56