2010-07-27 3 views
0

Мне нужно создать довольно сложную анимацию, включающую изображения в WPF, где изображение должно двигаться по круговой траектории. Here is a picture of what it looks like...Как я могу анимировать изображение по круговой траектории в WPF?

Вот моя XAML:

<ControlTemplate x:Key="ValveStyle" TargetType="{x:Type CheckBox}"> 
    <ControlTemplate.Resources> 
    <PathGeometry x:Key="CirclePathGeometry" PresentationOptions:Freeze="True"> 
     <PathGeometry.Figures> 
     <PathFigureCollection> 
      <PathFigure StartPoint="340,120"> 
      <PathFigure.Segments> 
       <PathSegmentCollection> 
       <ArcSegment Size="100,50" RotationAngle="0" IsLargeArc="False" SweepDirection="CounterClockwise" 
        Point="-30,120" /> 
       </PathSegmentCollection> 
      </PathFigure.Segments> 
      </PathFigure> 
     </PathFigureCollection> 
     </PathGeometry.Figures> 
    </PathGeometry> 
    </ControlTemplate.Resources> 
    <Viewbox Stretch="Uniform"> 
    <VisualStateManager.VisualStateGroups> 
     <VisualStateGroup x:Name="CheckStates"> 
     <VisualStateGroup.Transitions> 
      <VisualTransition GeneratedDuration="00:00:00.2000000" /> 
     </VisualStateGroup.Transitions> 
     <VisualState x:Name="Unchecked" /> 
     <VisualState x:Name="Checked"> 
      <Storyboard> 

      <!--DoubleAnimationUsingPath BeginTime="00:00:00" Storyboard.TargetName="image3" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Source="X" 
       DoubleAnimationUsingPath.PathGeometry="{StaticResource CirclePathGeometry}" /> 
     <DoubleAnimationUsingPath BeginTime="00:00:00" Storyboard.TargetName="image3" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Source="Y" 
       DoubleAnimationUsingPath.PathGeometry="{StaticResource CirclePathGeometry}" /--> 

      <MatrixAnimationUsingPath Storyboard.TargetName="Image3MatrixTransform" Storyboard.TargetProperty="Matrix" 
       MatrixAnimationUsingPath.PathGeometry="{StaticResource CirclePathGeometry}" /> 
      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" 
       Storyboard.TargetName="image1" 
       Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)"> 
       <SplineDoubleKeyFrame KeyTime="00:00:00" Value="-90" /> 
      </DoubleAnimationUsingKeyFrames> 
      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" 
       Storyboard.TargetName="image2" 
       Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)"> 
       <SplineDoubleKeyFrame KeyTime="00:00:00" Value="-90" /> 
      </DoubleAnimationUsingKeyFrames> 
      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" 
       Storyboard.TargetName="image" 
       Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)"> 
       <SplineDoubleKeyFrame KeyTime="00:00:00" Value="-90" /> 
      </DoubleAnimationUsingKeyFrames> 
      </Storyboard> 
     </VisualState> 
     </VisualStateGroup> 
    </VisualStateManager.VisualStateGroups> 
    <VisualStateManager.CustomVisualStateManager> 
     <ic:ExtendedVisualStateManager /> 
    </VisualStateManager.CustomVisualStateManager> 
    <Canvas Width="685" Height="527"> 
     <Image Source="/VT;component/Images/Valve121.1-Base.png" Stretch="Fill" /> 
     <Image x:Name="image" Source="/VT;component/Images/Valve121.1-LeftBar1.png" Stretch="Fill" 
      Canvas.Left="61.991" Canvas.Top="49.329" RenderTransformOrigin="0.286,0.5428"> 
     <Image.RenderTransform> 
      <TransformGroup> 
      <ScaleTransform /> 
      <SkewTransform /> 
      <RotateTransform /> 
      <TranslateTransform /> 
      </TransformGroup> 
     </Image.RenderTransform> 
     </Image> 
     <Image x:Name="image2" Source="/VT;component/Images/Valve121.1-RightBar.png" Stretch="Fill" 
      Canvas.Left="436.491" Canvas.Top="49.388" RenderTransformOrigin="0.249,0.756"> 
     <Image.RenderTransform> 
      <TransformGroup> 
      <ScaleTransform /> 
      <SkewTransform /> 
      <RotateTransform /> 
      <TranslateTransform /> 
      </TransformGroup> 
     </Image.RenderTransform> 
     </Image> 
     <Image x:Name="image3" Source="/VT;component/Images/Valve121.1-HzBar.png" Stretch="Fill" 
      Canvas.Left="277.491" Canvas.Top="58.345"> 
     <Image.RenderTransform> 
      <MatrixTransform x:Name="Image3MatrixTransform" /> 
     </Image.RenderTransform> 
     </Image> 
     <Image Source="/VT;component/Images/Valve121.1-Overlay.png" Stretch="Fill" /> 
     <Image x:Name="image1" Source="/VT;component/Images/Valve121.1-LeftBar2.png" Stretch="Fill" 
      Canvas.Left="129.824" Canvas.Top="24.661" RenderTransformOrigin="0.5,0.5"> 
     <Image.RenderTransform> 
      <TransformGroup> 
      <ScaleTransform /> 
      <SkewTransform /> 
      <RotateTransform /> 
      <TranslateTransform /> 
      </TransformGroup> 
     </Image.RenderTransform> 
     </Image> 
     <Path Stroke="Blue" StrokeThickness="10" RenderTransformOrigin="-0.333,-0.227"> 
     <Path.Data> 
      <PathGeometry> 
      <PathFigureCollection> 
       <PathFigure StartPoint="340,120"> 
       <PathFigure.Segments> 
        <PathSegmentCollection> 
        <ArcSegment Size="100,50" RotationAngle="0" IsLargeArc="False" SweepDirection="CounterClockwise" 
         Point="-30,120" /> 
        </PathSegmentCollection> 
       </PathFigure.Segments> 
       </PathFigure> 
      </PathFigureCollection> 
      </PathGeometry> 
     </Path.Data> 
     </Path> 
    </Canvas> 
    </Viewbox> 
</ControlTemplate> 

Я столкнулся с несколькими проблемами:

  • Изображение (image3) не кажется, правильно двигаться по пути я задал, так Думаю, я совершил ошибку там ...
  • Анимация изображения (image3) начинается после завершения всех других анимаций. Мне бы хотелось, чтобы все анимации начинались в одно и то же время.

Я пытался как DoubleAnimationUsingPath и MatrixAnimationUsingPath, но ни один из них не работал так, как я хочу. Можно ли смешивать анимацию ключевых кадров и анимацию пути?

Можно ли сделать такую ​​анимацию в WPF? Если да, то как я могу это достичь?

+0

Я рекомендую использовать Expression Blend для выполнения этих задач. В сети есть несколько учебных пособий, в которых объясняется, как решить задачи, о которых вы только что упоминали. Я не поклонник использования WYIWYG-приложений, но для анимации или создания сложных геометрий эти приложения обычно являются золотыми. – Torsten

+0

@Torsten: Я уже использую Blend, и я согласен, что это очень полезный инструмент, и я не могу себе представить, как это делать без него; -) ... но все же это продвинутая анимация, и я думаю, что я ударил предел Blend, или, кроме того, есть функция, которую я пропустил ... –

+0

ОК, я боялся, что вы скажете, что XD Тогда я уверен, что вы также знаете, что можно анимировать объекты параллельно. Я помню, как этот учебник начал для начала: http://www.kirupa.com/net/intro_blend_animation_pg1.htm Мое предположение было бы просто определить другую временную шкалу для вашего изображения3 (или определить отдельную временную шкалу для каждого объекта). Группировка также может помочь объединить все объекты. Может быть, эти намеки чересчур тривиальны, я надеюсь, что их нет. – Torsten

ответ

2

Определите MainWindow (или Page) класс следующим образом:

<Window x:Class="TestCustomTab.Window1" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="Window1" Height="300" Width="300"> 
    <Window.Resources> 
     <PathGeometry x:Key="path" Figures="M 0,50 A 50,50 0 1 1 100,50 " />   
     <Storyboard x:Key="ellipseSB"> 
      <DoubleAnimationUsingPath Storyboard.TargetName="ellipse" 
             Storyboard.TargetProperty="(Canvas.Left)" 
             PathGeometry="{StaticResource path}" 
             Duration="0:0:5" RepeatBehavior="Forever" 
             AutoReverse="True" Source="X" /> 
      <DoubleAnimationUsingPath Storyboard.TargetName="ellipse" 
             Storyboard.TargetProperty="(Canvas.Top)" 
             PathGeometry="{StaticResource path}" 
             Duration="0:0:5" RepeatBehavior="Forever" 
             AutoReverse="True" Source="Y" /> 
     </Storyboard>   
    </Window.Resources> 
    <Grid x:Name="grid"> 
     <Canvas> 
      <Ellipse x:Name="ellipse" Width="10" Height="10" Stroke="Black" Fill="Black" 
        RenderTransformOrigin="0.5,0.5" />    
      <Path Stroke="Red" StrokeThickness="1" Canvas.Left="5" Canvas.Top="5" 
        Data="{StaticResource path}"/> 
     </Canvas>   
     <Button VerticalAlignment="Bottom" Content="Start" Click="Button_Click"/> 
    </Grid> 
</Window> 

Затем в коде определить Button_Click обработчик события:

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    var sb = FindResource("ellipseSB") as Storyboard; 
    if (sb != null) sb.Begin(); 
} 

Это будет анимировать эллипс 10-на-10 точно вдоль который представляет собой половину окружности.

Надеюсь, это поможет.

0

У меня была такая же ситуация. Пример Юджина был очень полезен. Я немного растянул его, чтобы сделать полный круг:

<Window x:Class="TestCustomTab.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> 
    <Window.Resources> 
     <PathGeometry x:Key="pathUpperHalf" Figures="M 0,50 A 50,50 0 1 1 100,50 " /> 
     <PathGeometry x:Key="pathLowerHalf" Figures="M 100,50 A 50,50 0 1 1 0,50" /> 
     <Storyboard x:Key="ellipseSB" RepeatBehavior="Forever"> 
      <DoubleAnimationUsingPath Storyboard.TargetName="ellipse" 
       Storyboard.TargetProperty="(Canvas.Left)" 
       PathGeometry="{StaticResource pathUpperHalf}" 
       Duration="0:0:1" RepeatBehavior="1x" AutoReverse="False" BeginTime="0:0:0" Source="X" /> 
      <DoubleAnimationUsingPath Storyboard.TargetName="ellipse" 
       Storyboard.TargetProperty="(Canvas.Top)" 
       PathGeometry="{StaticResource pathUpperHalf}" 
       Duration="0:0:1" RepeatBehavior="1x" AutoReverse="False" BeginTime="0:0:0" Source="Y" /> 

      <DoubleAnimationUsingPath Storyboard.TargetName="ellipse" 
       Storyboard.TargetProperty="(Canvas.Left)" 
       PathGeometry="{StaticResource pathLowerHalf}" 
       Duration="0:0:1" RepeatBehavior="1x" AutoReverse="False" BeginTime="0:0:1" Source="X" /> 
      <DoubleAnimationUsingPath Storyboard.TargetName="ellipse" 
       Storyboard.TargetProperty="(Canvas.Top)" 
       PathGeometry="{StaticResource pathLowerHalf}" 
       Duration="0:0:1" RepeatBehavior="1x" AutoReverse="False" BeginTime="0:0:1" Source="Y" /> 
     </Storyboard> 
    </Window.Resources> 
    <Grid x:Name="grid"> 
     <Canvas> 
      <Ellipse x:Name="ellipse" Width="10" Height="10" Stroke="Black" Fill="Black" RenderTransformOrigin="0.5,0.5" /> 
      <Path Stroke="Blue" StrokeThickness="1" Canvas.Left="5" Canvas.Top="5" Data="{StaticResource pathUpperHalf}"/> 
      <Path Stroke="Red" StrokeThickness="1" Canvas.Left="5" Canvas.Top="5" Data="{StaticResource pathLowerHalf}"/> 
     </Canvas> 
     <Button VerticalAlignment="Bottom" Content="Start" Click="Button_Click"/> 
    </Grid> 
</Window> 
+0

FWIW: нет необходимости объявлять две разные пары анимаций, чтобы получить полный круг. Просто протяните исходный круг, чтобы вернуться к исходной точке; единственная «gotcha» заключается в том, что если вы точно укажете одну и ту же точку, ничего не получится. Но вы можете вычесть очень маленькую сумму (например, 0,0001) из одной из координат (в зависимости от того, какая из них должна быть самой быстрой, ближе к концу ... 'Y' в приведенном выше примере), а затем WPF будет знать, что нужно пройти долгий путь , Например. используйте 'Рисунки =" M 0,50 A 50,50 0 1 1 0,49,9999 ". –