2015-06-02 3 views
1

У меня есть WPF StoryboardRepeatBehavior=Forever), содержащий две анимации DoubleAnimationUsingPath. Эти анимации отслеживают круговой путь, который я создаю, добавляя EllipseGeometry. Одна анимация используется для управления положением X, а другая анимация используется для управления положением Y другого объекта, который появляется на орбите с использованием кругового пути.Play DoubleAnimationUsingPath in reverse

Анимация всегда следует по пути по часовой стрелке и всегда начинается посередине в правой части круга. Мне нужно заставить анимацию играть в обратном направлении (т. Е. Против часовой стрелки вдоль пути). В идеале я также хотел бы иметь возможность контролировать стартовую позицию, но сейчас это не является необходимостью.

Свойство AutoReverse на анимации делает то, что я хочу, но, очевидно, тогда он чередуется между по часовой стрелкой и против часовой стрелки - и мне нужна анимация для цикла, всегда в направлении против часовой стрелки.

Я также попытался использовать ScaleTransform с ScaleX = -1, чтобы перевернуть эллипс, надеясь, что это поможет - но это не так.

Есть ли способ заставить DoubleAnimationUsingPath следовать определенному направлению вдоль пути?

ответ

1

Вы можете переключаться между двумя путями с одинаковыми координатами, но обратные направления. здесь приведен пример с использованием MatrixAnimationUsingPath, в котором направление анимации является cw, когда элемент UI загружается, и он изменяется на ccw, когда указатель мыши входит в синий прямоугольник.

<Canvas ClipToBounds="False" Width="400" Height="400"> 
     <Path StrokeThickness="10" StrokeDashArray="" StrokeDashCap="Flat" StrokeDashOffset="0" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat" StrokeLineJoin="Miter" StrokeMiterLimit="10" Stroke="#000000"> 
      <Path.Data> 
       <PathGeometry Figures="M 150,250 C 150,120 300,120 300,250 C 300,390 150,390 150,250 Z" /> 
      </Path.Data> 
     </Path> 
     <Rectangle Fill="Blue" RenderTransformOrigin="0.5,0.5" Width="10" Height="10" Margin="-5"> 
      <Rectangle.RenderTransform> 
       <TransformGroup> 
        <MatrixTransform x:Name="tt"> 
         <MatrixTransform.Matrix> 
          <Matrix /> 
         </MatrixTransform.Matrix> 
        </MatrixTransform> 
       </TransformGroup> 
      </Rectangle.RenderTransform> 
      <Rectangle.Triggers> 
       <EventTrigger RoutedEvent="FrameworkElement.Loaded"> 
        <BeginStoryboard> 
         <Storyboard> 
          <MatrixAnimationUsingPath Duration="0:0:05" Storyboard.TargetName="tt" 
                 Storyboard.TargetProperty="Matrix" 
                 AutoReverse="False" 
                 DoesRotateWithTangent="True" 
                 RepeatBehavior="Forever" 
                > 
           <MatrixAnimationUsingPath.PathGeometry> 
            <PathGeometry Figures="M 150,250 C 150,120 300,120 300,250 C 300,390 150,390 150,250 Z"> 
            </PathGeometry> 
           </MatrixAnimationUsingPath.PathGeometry> 
          </MatrixAnimationUsingPath> 
         </Storyboard> 
        </BeginStoryboard> 
       </EventTrigger> 
       <EventTrigger RoutedEvent="FrameworkElement.MouseEnter"> 
        <BeginStoryboard> 
         <Storyboard> 
          <MatrixAnimationUsingPath Duration="0:0:05" Storyboard.TargetName="tt" 
                 Storyboard.TargetProperty="Matrix" 
                 AutoReverse="False" 
                 DoesRotateWithTangent="True" 
                 RepeatBehavior="Forever" 
                > 
           <MatrixAnimationUsingPath.PathGeometry> 
            <PathGeometry Figures="M 150,250 C 150,390 300,390 300,250 C 300,120 150,120 150,250 Z" > 
            </PathGeometry> 
           </MatrixAnimationUsingPath.PathGeometry> 
          </MatrixAnimationUsingPath> 
         </Storyboard> 
        </BeginStoryboard> 
       </EventTrigger> 
      </Rectangle.Triggers> 
     </Rectangle> 
    </Canvas> 
+0

Спасибо за предложение. Похоже, что ключ к этому состоит в том, что есть два отдельных пути: один для направления по часовой стрелке и один для направления против часовой стрелки. Я надеялся найти решение, которое позволит анимации использовать один путь - или, по крайней мере, программно манипулировать путем для динамического создания альтернатив по часовой стрелке и против часовой стрелки. – John

1

Альтернатива DoubleAnimationUsingPath будет пользовательские анимации, которая обеспечивает значение синусов. Он имеет свойство Amplitude, которое контролирует амплитуду и по ее знаку также направление синусовой анимации. Существует также свойство StartAngle, которое контролирует, с какого угла начинается анимация.

public class SinusAnimation : DoubleAnimationBase 
{ 
    public static readonly DependencyProperty AmplitudeProperty = 
     DependencyProperty.Register(
      "Amplitude", typeof(double), typeof(SinusAnimation)); 

    public static readonly DependencyProperty StartAngleProperty = 
     DependencyProperty.Register(
      "StartAngle", typeof(double), typeof(SinusAnimation)); 

    public double Amplitude 
    { 
     get { return (double)GetValue(AmplitudeProperty); } 
     set { SetValue(AmplitudeProperty, value); } 
    } 

    public double StartAngle 
    { 
     get { return (double)GetValue(StartAngleProperty); } 
     set { SetValue(StartAngleProperty, value); } 
    } 

    protected override double GetCurrentValueCore(double defaultOriginValue, 
     double defaultDestinationValue, AnimationClock animationClock) 
    { 
     var result = defaultOriginValue; 
     var p = animationClock.CurrentProgress; 

     if (p.HasValue) 
     { 
      result = Amplitude * Math.Sin(
       p.Value * Math.PI * 2d + StartAngle * Math.PI/180d); 
     } 

     return result; 
    } 

    protected override Freezable CreateInstanceCore() 
    { 
     return new SinusAnimation(); 
    } 
} 

Это простой XAML, который создает круговое движение небольшого синего круга. По разным Амплитудам он мог бы также создавать эллиптические траектории, а также разными StartAngles также все виды фигур Лиссажу.

<Canvas Margin="200"> 
    <Path Fill="Blue"> 
     <Path.Data> 
      <EllipseGeometry RadiusX="10" RadiusY="10"/> 
     </Path.Data> 
     <Path.Triggers> 
      <EventTrigger RoutedEvent="Loaded"> 
       <BeginStoryboard> 
        <Storyboard Duration="0:0:2" RepeatBehavior="Forever"> 
         <local:SinusAnimation 
          Storyboard.TargetProperty="(Canvas.Left)" 
          Amplitude="100" 
          Duration="0:0:2" RepeatBehavior="Forever"/> 
         <local:SinusAnimation 
          Storyboard.TargetProperty="(Canvas.Top)" 
          Amplitude="100" StartAngle="90" 
          Duration="0:0:2" RepeatBehavior="Forever"/> 
        </Storyboard> 
       </BeginStoryboard> 
      </EventTrigger> 
     </Path.Triggers> 
    </Path> 
</Canvas> 

Edit: Для того, чтобы обратить на DoubleAnmationUsingPath вы можете просто установить Transform свойство используется PathGeometry к соответствующему ScaleTransform:

<PathGeometry x:Key="path"> 
    <PathGeometry.Transform> 
     <ScaleTransform ScaleX="-1"/> 
    </PathGeometry.Transform> 
    ... 
</PathGeometry> 
+1

Ницца! когда я изменил «StartAngle» на «270», поворот был отменен. –

+2

Также, когда вы устанавливаете одну Амплитуду в отрицательное значение. – Clemens

+0

Спасибо! Это действительно хорошо работает для круга, хотя я надеялся найти решение, которое будет работать с произвольным путем. – John