[英]Easing animation 'twitches' when it finishes
我正在使用Microsoft Interactivity和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>
由于这似乎是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,但是如果您只想让它对双重动画起作用,则可能会遗漏很多。
希望这对任何人有帮助!
我注意到的一件事, 错! CenterX
和CenterY
应该是一个十进制且小于1,例如CenterY="0.45" CenterX="0.4"
更新
花了一些时间在ChangePropertyAction
播放后,我发现无论您选择哪种缓动功能,动画都将始终具有闪烁效果。
我认为这是一个错误...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.