WPF Animation, которая изгибается и следует некоторой геометрии пути

Хорошо, поэтому я работаю на экране загрузки, и я хочу немного его разжечь.

В основном то, что я пытаюсь сделать, - это анимировать объект по данным геометрии пути... Я подчеркиваю "вдоль", потому что сохранение фиксированного объекта по пути по касательной - это не то, что я хотел бы сделать

Это лучшее представление о том, что я пытаюсь сделать:

enter image description here

Я могу использовать матричное преобразование для отправки этого пограничного элемента по пути, но оно завершается как тангенциальная анимация, которая перемещается и вращается с контуром, но не сгибается, чтобы соответствовать форме пути... Здесь является примером этого:

<Border Background="Black" BorderBrush="Transparent" Width="20" Height="20">
<Border.RenderTransform>
    <MatrixTransform x:Name="MatrixT">
        <MatrixTransform.Matrix>
            <Matrix/>
        </MatrixTransform.Matrix>
    </MatrixTransform>
</Border.RenderTransform>
<Border.Triggers>
    <EventTrigger RoutedEvent="Border.Loaded">
        <BeginStoryboard>
            <Storyboard>
                <MatrixAnimationUsingPath Storyboard.TargetName="MatrixT" Storyboard.TargetProperty="Matrix" DoesRotateWithTangent="True" Duration="0:0:5" RepeatBehavior="Forever">
                    <MatrixAnimationUsingPath.PathGeometry>
                        <PathGeometry Figures="M201.1,50.501C201.1,78.138,178.737,100.501,151.1,100.501L150.799,100.501C123.162,100.501,114.933,77.834,100.8,50.501L100.8,50.5C86.666,23.167,78.437,0.5,50.8,0.5L50.5,0.5C22.863,0.5,0.500000000000014,22.863,0.500000000000014,50.5L0.500000000000014,50.501C0.500000000000014,78.138,22.863,100.501,50.5,100.501L50.8,100.501C78.437,100.501,86.666,77.834,100.8,50.501L100.8,50.5C114.933,23.167,123.162,0.5,150.799,0.5L151.1,0.5C178.736,0.5,201.1,22.863,201.1,50.501L201.1,50.501z" PresentationOptions:Freeze="True"/>
                    </MatrixAnimationUsingPath.PathGeometry>
                </MatrixAnimationUsingPath>
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
</Border.Triggers>

Я придумал альтернативное решение, которое выглядит очень резким, но я хотел передать этот вопрос сообществу, чтобы узнать, есть ли у них какие-либо идеи о том, как выполнить эту задачу (или, если это вообще возможно).. Я сделал несколько обширных поисковых запросов по этому вопросу и не придумал ничего о том, как это сделать эффективным способом.

Требования:

  • Он должен следовать (или "согнуть" ) путь
  • Он должен иметь возможность масштабировать размер, не разбивая анимацию (многие из представлений анимации штрихов, которые я видел, могут работать только на одном уровне без повторной настройки свойств анимации)... viewbox вполне приемлемо для выполните этот

Если форма может быть сужена и затухать на задней стороне, что будет еще большим плюсом (см. изображение выше), но это может быть больше, чем возможно

EDIT: Чтобы уточнить, что я имею в виду под "изгибом"... Я имею в виду рисунок B ниже... цифра A - это стандарт, который я традиционно видел:

enter image description here

Ответы

Ответ 1

Морфинг вашей фигуры на путь будет очень сложным в WPF. Однако существует близкое приближение, оживляя два отдельных пути, а также одновременно анимируя две области отсечения.

Ниже приводится XAML для приближения того, что вы хотите. Если вы внимательно посмотрите на точку пересечения символа бесконечности, вы заметите небольшой разрыв в гладкости затенения во время перехода. Это потому, что я был немного произволен в настройках точек начала, конца и смещения для объектов LinearGradientBrush. Небольшая работа над ними сгладит этот переход. Вы даже можете выбрать анимацию свойств на кистях, чтобы помочь с этим.

<Window x:Class="AnimationTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        Background="#FF486CBF">
  <Viewbox>
    <Grid>
      <Canvas Width="50" Height="50"
              HorizontalAlignment="Left"
              VerticalAlignment="Top">
        <Canvas.Clip>
          <RectangleGeometry Rect="0,0,50,55">
            <RectangleGeometry.Transform>
              <TranslateTransform x:Name="_clip1"/>
            </RectangleGeometry.Transform>
          </RectangleGeometry>
        </Canvas.Clip>
        <Path StrokeStartLineCap="Round"
              StrokeEndLineCap="Round"
              StrokeThickness="10"
              RenderTransformOrigin="0.5,0.8571"
              Data="M 5,25 c 0,-25 40,-25 40,0">
          <Path.Stroke>
            <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
              <GradientStop Color="#FFFFFFFF" Offset="0"/>
              <GradientStop Color="#00FFFFFF" Offset="0.7"/>
            </LinearGradientBrush>
          </Path.Stroke>
          <Path.RenderTransform>
            <RotateTransform x:Name="_rot1" />
          </Path.RenderTransform>
          <Path.Triggers>
            <EventTrigger RoutedEvent="Path.Loaded">
              <BeginStoryboard>
                <Storyboard>
                  <DoubleAnimation From="360" To="0"
                                   Duration="0:0:3"
                                   RepeatBehavior="Forever"
                                   Storyboard.TargetName="_rot1"
                                   Storyboard.TargetProperty="Angle"/>
                  <DoubleAnimationUsingKeyFrames Storyboard.TargetName="_clip1"
                         Storyboard.TargetProperty="Y"
                         RepeatBehavior="Forever">
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
                    <DiscreteDoubleKeyFrame KeyTime="0:0:1.5" Value="25"/>
                    <DiscreteDoubleKeyFrame KeyTime="0:0:2.8" Value="55"/>
                    <DiscreteDoubleKeyFrame KeyTime="0:0:4.5" Value="-30"/>
                    <DiscreteDoubleKeyFrame KeyTime="0:0:5.8" Value="0"/>
                    <DiscreteDoubleKeyFrame KeyTime="0:0:6" Value="0"/>
                  </DoubleAnimationUsingKeyFrames>
                </Storyboard>
              </BeginStoryboard>
            </EventTrigger>
          </Path.Triggers>
        </Path>
      </Canvas>

      <Canvas Width="50" Height="50"
              HorizontalAlignment="Left"
              VerticalAlignment="Top"
              Margin="40,0,0,0">
        <Canvas.Clip>
          <RectangleGeometry Rect="0,0,50,55">
            <RectangleGeometry.Transform>
              <TranslateTransform x:Name="_clip2"/>
            </RectangleGeometry.Transform>
          </RectangleGeometry>
        </Canvas.Clip>
        <Path StrokeStartLineCap="Round"
              StrokeEndLineCap="Round"
              StrokeThickness="10"
              RenderTransformOrigin="0.5,0.8571"
              Data="M 5,25 c 0,-25 40,-25 40,0">
          <Path.Stroke>
            <LinearGradientBrush StartPoint="1,0" EndPoint="0,0">
              <GradientStop Color="#FFFFFFFF" Offset="0"/>
              <GradientStop Color="#00FFFFFF" Offset="0.7"/>
            </LinearGradientBrush>
          </Path.Stroke>
          <Path.RenderTransform>
            <RotateTransform x:Name="_rot2" />
          </Path.RenderTransform>
          <Path.Triggers>
            <EventTrigger RoutedEvent="Path.Loaded">
              <BeginStoryboard>
                <Storyboard>
                  <DoubleAnimation From="0" To="360"
                         Duration="0:0:3"
                         RepeatBehavior="Forever"
                         Storyboard.TargetName="_rot2"
                         Storyboard.TargetProperty="Angle"/>
                  <DoubleAnimationUsingKeyFrames Storyboard.TargetName="_clip2"
                         Storyboard.TargetProperty="Y"
                         RepeatBehavior="Forever">
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="55"/>
                    <DiscreteDoubleKeyFrame KeyTime="0:0:1.5" Value="-30"/>
                    <DiscreteDoubleKeyFrame KeyTime="0:0:2.8" Value="0"/>
                    <DiscreteDoubleKeyFrame KeyTime="0:0:4.5" Value="25"/>
                    <DiscreteDoubleKeyFrame KeyTime="0:0:5.8" Value="55"/>
                    <DiscreteDoubleKeyFrame KeyTime="0:0:6" Value="55"/>
                  </DoubleAnimationUsingKeyFrames>
                </Storyboard>
              </BeginStoryboard>
            </EventTrigger>
          </Path.Triggers>
        </Path>
      </Canvas>
    </Grid>
  </Viewbox>
</Window>

Важно отметить, что области отсечения должны применяться к объектам Canvas. Если они применяются к объектам Path, как обычно, для изображения, область отсечения затем поворачивается вместе с Path на RenderTrasform. Не желаемый эффект.

Ответ 2

Вы могли бы просто наложить много кругов на путь и оживить их диаметры.