Облегчение анимации «дергается», когда она заканчивается - PullRequest
5 голосов
/ 20 октября 2011

Я использую Microsoft Interactive и Microsoft Interactions, чтобы вращать объект на основе свойства в моем коде. Чтобы сделать вращение более плавным, я добавил функцию замедления. Он прекрасно выполняет анимацию, но когда он достигает конца анимации для 1 разделенного кадра, вращение сбрасывается до значения, которое было до анимации, а затем переключается обратно на значение после вращения, заставляя его «дергаться» взад-вперед , Это происходит только на EaseOut.

<i:Interaction.Triggers>
    <ie:PropertyChangedTrigger Binding="{Binding Rotation}">
        <ie:ChangePropertyAction TargetName="RotateTransformer" PropertyName="Angle" Value="{Binding Rotation}" Duration="0:0:2">
            <ie:ChangePropertyAction.Ease>                        
                <BackEase EasingMode="EaseOut" Amplitude="1.2" />
            </ie:ChangePropertyAction.Ease>
        </ie:ChangePropertyAction>
    </ie:PropertyChangedTrigger>
</i:Interaction.Triggers>
<Path Stroke="Black" Fill="Gray">
    <Path.RenderTransform>
        <RotateTransform x:Name="RotateTransformer" CenterX="64" CenterY="105" />
    </Path.RenderTransform>
    <Path.Data>
        <PathGeometry>
            <PathFigureCollection>
                <PathFigure StartPoint="64,0" >
                    <LineSegment Point="39,110" />
                    <LineSegment Point="64, 70" />
                    <LineSegment Point="39,180" />
                    <LineSegment Point="89, 180" />
                    <LineSegment Point="64,70"/>
                    <LineSegment Point="89,110" />
                    <LineSegment Point="64,0" />
                </PathFigure>
            </PathFigureCollection>
        </PathGeometry>
    </Path.Data>
</Path>

Ответы [ 2 ]

4 голосов
/ 01 августа 2012

Поскольку это кажется ошибкой в ​​реализации класса ChangePropertyAction, я решил, что лучший способ докопаться до сути этого - бросить сборку в ваше любимое приложение в стиле отражателя и посмотреть на внутренности реализации..

Вот выдержка (из нее многое еще не вышло, но есть соответствующий бит):

  public class ChangePropertyAction : TargetedTriggerAction<object>
  {
    /* some dependency properties here, like DurationProperty, ValueProperty, etc... */


    protected override void Invoke(object parameter)
    {
       /* a lot of validation here, but skimming over that mostly. Valid input results in a call to AnimatePropertyChange() */
    }

    private void AnimatePropertyChange(PropertyInfo propertyInfo, object fromValue, object newValue)
    {
      Storyboard storyboard = new Storyboard();
      Timeline timeline = !typeof (double).IsAssignableFrom(propertyInfo.PropertyType) 
                ? (!typeof (Color).IsAssignableFrom(propertyInfo.PropertyType)
                ? (!typeof (Point).IsAssignableFrom(propertyInfo.PropertyType)
                ? this.CreateKeyFrameAnimation(fromValue, newValue)
                    : this.CreatePointAnimation((Point) fromValue, (Point) newValue))
                    : this.CreateColorAnimation((Color) fromValue, (Color) newValue))
                    : this.CreateDoubleAnimation((double) fromValue, (double) newValue);
      timeline.Duration = this.Duration;
      storyboard.Children.Add(timeline);
      Storyboard.SetTarget((Timeline) storyboard, (DependencyObject) this.Target);
      Storyboard.SetTargetProperty((Timeline) storyboard, new PropertyPath(propertyInfo.Name, new object[0]));
      storyboard.Completed += (EventHandler) ((o, e) => propertyInfo.SetValue(this.Target, newValue, new object[0]));
      storyboard.FillBehavior = FillBehavior.Stop;
      storyboard.Begin();
    }

    private static object GetCurrentPropertyValue(object target, PropertyInfo propertyInfo)
    {
      FrameworkElement frameworkElement = target as FrameworkElement;
      target.GetType();
      object obj = propertyInfo.GetValue(target, (object[]) null);
      if (frameworkElement != null && (propertyInfo.Name == "Width" || propertyInfo.Name == "Height") && double.IsNaN((double) obj))
        obj = !(propertyInfo.Name == "Width") ? (object) frameworkElement.ActualHeight : (object) frameworkElement.ActualWidth;
      return obj;
    }

    private Timeline CreateDoubleAnimation(double fromValue, double newValue)
    {
      return (Timeline) new DoubleAnimation()
      {
        From = new double?(fromValue),
        To = new double?(newValue),
        EasingFunction = this.Ease
      };
    }
  }

Если вы хотите посмотреть полный код, запустите его через DotPeekили ILSpy самостоятельно, оба бесплатны: -)

Итак, в конце концов, все, что он делает, это проверяет входные данные, смотрит на тип значения и создает раскадровку с анимацией перехода, соответствующей типу свойства.Эффект 'мерцания' на самом деле представляет собой значение, кратковременно возвращающееся к своему первоначальному значению (то, которое фактически связано), когда анимация завершена, после чего привязка обновляется, чтобы отразить новое значение.Причина такого поведения кроется в одной единственной настройке свойства на раскадровке:

storyboard.FillBehavior = FillBehavior.Stop;

Этот FillBehavior определяет, что происходит, когда Временная шкала (раскадровка в данном случае) достигает своего конца.У MSDN есть это, чтобы сказать:

HoldEnd : После того, как он достигает конца своего активного периода, временная шкала задерживает свое продвижение до конца периодов активности и удержания своего родителя.

Стоп : временная шкала останавливается, если она выходит за пределы активного периода, в то время как его родитель находится внутри активного периода.

Если мы просто изменим это свойство для установкиFillBehavior.HoldEnd, мерцание исчезло.Недостатком является то, что вам придется повторно реализовать это действие TriggerAction, но вы, вероятно, можете многое пропустить, если просто хотите, чтобы он работал для двойной анимации.

Надеюсь, это кому-нибудь поможет!

2 голосов
/ 20 октября 2011

Одна вещь, которую я заметил, CenterX и CenterY должны быть десятичными и меньше 1, например. CenterY="0.45" CenterX="0.4" НЕПРАВИЛЬНО!

UPDATE

Потратив некоторое время на игру с ChangePropertyAction, я обнаружил, что анимация всегда будет иметь такое мерцание, независимо от того, какую функцию замедления вы выберете.

Я думаю, что это ошибка ...

...