轻松上色动画
Color Animation with ease
我一直在关注制作彩色动画的问题。
我可以创建动画,在动画再次开始之前它 运行 没问题。有那么一瞬间,感觉动画已经started/stopped了那么一瞬间。我希望动画 运行 平滑,这样它就不会在颜色上显示任何重新启动的效果。可以吗?
我正在使用以下代码:
<Storyboard x:Key="GradientAnimation"
RepeatBehavior="Forever"
Storyboard.TargetName="BackgroundBrush"
SpeedRatio="0.3">
<ColorAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.Background).(LinearGradientBrush.GradientStops)[0].(GradientStop.Color)"
EnableDependentAnimation="True"
BeginTime="-0:0:0.5">
<LinearColorKeyFrame KeyTime="0:0:0" Value="Black"/>
<LinearColorKeyFrame KeyTime="0:0:1" Value="Red"/>
<LinearColorKeyFrame KeyTime="0:0:2" Value="Black"/>
<LinearColorKeyFrame KeyTime="0:0:3" Value="Red"/>
<LinearColorKeyFrame KeyTime="0:0:4" Value="Black"/>
<LinearColorKeyFrame KeyTime="0:0:5" Value="Red"/>
<LinearColorKeyFrame KeyTime="0:0:6" Value="Black"/>
<LinearColorKeyFrame KeyTime="0:0:7" Value="Red"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.Background).(LinearGradientBrush.GradientStops)[1].(GradientStop.Color)"
EnableDependentAnimation="True">
<LinearColorKeyFrame KeyTime="0:0:0" Value="Red"/>
<LinearColorKeyFrame KeyTime="0:0:1" Value="Black"/>
<LinearColorKeyFrame KeyTime="0:0:2" Value="Red"/>
<LinearColorKeyFrame KeyTime="0:0:3" Value="Black"/>
<LinearColorKeyFrame KeyTime="0:0:4" Value="Red"/>
<LinearColorKeyFrame KeyTime="0:0:5" Value="Black"/>
<LinearColorKeyFrame KeyTime="0:0:6" Value="Red"/>
<LinearColorKeyFrame KeyTime="0:0:7" Value="Black"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
然后我在代码隐藏中启动这个动画:
((Storyboard)Resources["GradientAnimation"]).Begin();
也许有某种 'easing' 方法混淆了动画的开始和停止,因此它看起来像长 运行ning 动画一样流畅。有什么建议吗?
您可以尝试 EasingColorKeyFrame
,但动画永远不会流畅,因为它在 UI 线程(即 EnableDependentAnimation="True"
)上 运行。
这里有一些好消息和坏消息。好处是我们现在在 Composition 图层级别有新的渐变画笔 API,这意味着它是完全可动画的并且 运行 脱离了 UI 线程.因此,在性能方面,它将比当前的 Storyboard
解决方案好得多。但它仅在 Windows 10 Insider Preview 16225 之后可用,这意味着它不适用于除内部人员之外的大多数当前用户。
但是,我仍然会post这里的这个新解决方案以供将来参考,因为目前还没有关于这个主题的示例。
请注意,我为动画添加了一些额外的调味料以使其更有趣。如果您只想对颜色进行动画处理,请随意移动 EndPoint
和 RotationAngleInDegrees
动画(我使用 EndPoint
动画在启动时从纯色背景动画到渐变动画应用程序和 RotationAngleInDegrees
永久旋转渐变画笔)。
var compositor = Window.Current.Compositor;
// Initially, we set the end point to be (0,0) 'cause we want to animate it at start.
// If you don't want this behavior, simply set it to a different value within (1,1).
_gradientBrush = compositor.CreateLinearGradientBrush();
_gradientBrush.EndPoint = Vector2.Zero;
// Create gradient initial colors.
var gradientStop1 = compositor.CreateColorGradientStop();
gradientStop1.Offset = 0.0f;
gradientStop1.Color = GradientStop1StartColor;
var gradientStop2 = compositor.CreateColorGradientStop();
gradientStop2.Offset = 1.0f;
gradientStop2.Color = GradientStop2StartColor;
_gradientBrush.ColorStops.Add(gradientStop1);
_gradientBrush.ColorStops.Add(gradientStop2);
// Assign the gradient brush to the Root element's Visual.
_backgroundVisual = compositor.CreateSpriteVisual();
_backgroundVisual.Brush = _gradientBrush;
ElementCompositionPreview.SetElementChildVisual(Root, _backgroundVisual);
// There are 3 animations going on here.
// First, we kick off an EndPoint offset animation to create an special entrance scene.
// Once it's finished, we then kick off TWO other animations simultaneously.
// These TWO animations include a set of gradient stop color animations and
// a rotation animation that rotates the gradient brush.
var linearEase = compositor.CreateLinearEasingFunction();
var batch = compositor.CreateScopedBatch(CompositionBatchTypes.Animation);
batch.Completed += (s, e) =>
{
StartGradientColorAnimations();
StartGradientRotationAnimation();
};
var endPointOffsetAnimation = compositor.CreateVector2KeyFrameAnimation();
endPointOffsetAnimation.Duration = TimeSpan.FromSeconds(3);
endPointOffsetAnimation.InsertKeyFrame(1.0f, Vector2.One);
_gradientBrush.StartAnimation(nameof(_gradientBrush.EndPoint), endPointOffsetAnimation);
batch.End();
void StartGradientColorAnimations()
{
var color1Animation = compositor.CreateColorKeyFrameAnimation();
color1Animation.Duration = TimeSpan.FromSeconds(10);
color1Animation.IterationBehavior = AnimationIterationBehavior.Forever;
color1Animation.Direction = AnimationDirection.Alternate;
color1Animation.InsertKeyFrame(0.0f, GradientStop1StartColor, linearEase);
color1Animation.InsertKeyFrame(0.5f, Color.FromArgb(255, 65, 88, 208), linearEase);
color1Animation.InsertKeyFrame(1.0f, Color.FromArgb(255, 43, 210, 255), linearEase);
gradientStop1.StartAnimation(nameof(gradientStop1.Color), color1Animation);
var color2Animation = compositor.CreateColorKeyFrameAnimation();
color2Animation.Duration = TimeSpan.FromSeconds(10);
color2Animation.IterationBehavior = AnimationIterationBehavior.Forever;
color2Animation.Direction = AnimationDirection.Alternate;
color2Animation.InsertKeyFrame(0.0f, GradientStop2StartColor, linearEase);
color1Animation.InsertKeyFrame(0.5f, Color.FromArgb(255, 200, 80, 192), linearEase);
color2Animation.InsertKeyFrame(1.0f, Color.FromArgb(255, 43, 255, 136), linearEase);
gradientStop2.StartAnimation(nameof(gradientStop2.Color), color2Animation);
}
void StartGradientRotationAnimation()
{
var rotationAnimation = compositor.CreateScalarKeyFrameAnimation();
rotationAnimation.Duration = TimeSpan.FromSeconds(15);
rotationAnimation.IterationBehavior = AnimationIterationBehavior.Forever;
rotationAnimation.InsertKeyFrame(1.0f, 360.0f, linearEase);
_gradientBrush.StartAnimation(nameof(_gradientBrush.RotationAngleInDegrees), rotationAnimation);
}
这是一个有效的 sample,下面是它的样子。 :)
我一直在关注
我可以创建动画,在动画再次开始之前它 运行 没问题。有那么一瞬间,感觉动画已经started/stopped了那么一瞬间。我希望动画 运行 平滑,这样它就不会在颜色上显示任何重新启动的效果。可以吗?
我正在使用以下代码:
<Storyboard x:Key="GradientAnimation"
RepeatBehavior="Forever"
Storyboard.TargetName="BackgroundBrush"
SpeedRatio="0.3">
<ColorAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.Background).(LinearGradientBrush.GradientStops)[0].(GradientStop.Color)"
EnableDependentAnimation="True"
BeginTime="-0:0:0.5">
<LinearColorKeyFrame KeyTime="0:0:0" Value="Black"/>
<LinearColorKeyFrame KeyTime="0:0:1" Value="Red"/>
<LinearColorKeyFrame KeyTime="0:0:2" Value="Black"/>
<LinearColorKeyFrame KeyTime="0:0:3" Value="Red"/>
<LinearColorKeyFrame KeyTime="0:0:4" Value="Black"/>
<LinearColorKeyFrame KeyTime="0:0:5" Value="Red"/>
<LinearColorKeyFrame KeyTime="0:0:6" Value="Black"/>
<LinearColorKeyFrame KeyTime="0:0:7" Value="Red"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.Background).(LinearGradientBrush.GradientStops)[1].(GradientStop.Color)"
EnableDependentAnimation="True">
<LinearColorKeyFrame KeyTime="0:0:0" Value="Red"/>
<LinearColorKeyFrame KeyTime="0:0:1" Value="Black"/>
<LinearColorKeyFrame KeyTime="0:0:2" Value="Red"/>
<LinearColorKeyFrame KeyTime="0:0:3" Value="Black"/>
<LinearColorKeyFrame KeyTime="0:0:4" Value="Red"/>
<LinearColorKeyFrame KeyTime="0:0:5" Value="Black"/>
<LinearColorKeyFrame KeyTime="0:0:6" Value="Red"/>
<LinearColorKeyFrame KeyTime="0:0:7" Value="Black"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
然后我在代码隐藏中启动这个动画:
((Storyboard)Resources["GradientAnimation"]).Begin();
也许有某种 'easing' 方法混淆了动画的开始和停止,因此它看起来像长 运行ning 动画一样流畅。有什么建议吗?
您可以尝试 EasingColorKeyFrame
,但动画永远不会流畅,因为它在 UI 线程(即 EnableDependentAnimation="True"
)上 运行。
这里有一些好消息和坏消息。好处是我们现在在 Composition 图层级别有新的渐变画笔 API,这意味着它是完全可动画的并且 运行 脱离了 UI 线程.因此,在性能方面,它将比当前的 Storyboard
解决方案好得多。但它仅在 Windows 10 Insider Preview 16225 之后可用,这意味着它不适用于除内部人员之外的大多数当前用户。
但是,我仍然会post这里的这个新解决方案以供将来参考,因为目前还没有关于这个主题的示例。
请注意,我为动画添加了一些额外的调味料以使其更有趣。如果您只想对颜色进行动画处理,请随意移动 EndPoint
和 RotationAngleInDegrees
动画(我使用 EndPoint
动画在启动时从纯色背景动画到渐变动画应用程序和 RotationAngleInDegrees
永久旋转渐变画笔)。
var compositor = Window.Current.Compositor;
// Initially, we set the end point to be (0,0) 'cause we want to animate it at start.
// If you don't want this behavior, simply set it to a different value within (1,1).
_gradientBrush = compositor.CreateLinearGradientBrush();
_gradientBrush.EndPoint = Vector2.Zero;
// Create gradient initial colors.
var gradientStop1 = compositor.CreateColorGradientStop();
gradientStop1.Offset = 0.0f;
gradientStop1.Color = GradientStop1StartColor;
var gradientStop2 = compositor.CreateColorGradientStop();
gradientStop2.Offset = 1.0f;
gradientStop2.Color = GradientStop2StartColor;
_gradientBrush.ColorStops.Add(gradientStop1);
_gradientBrush.ColorStops.Add(gradientStop2);
// Assign the gradient brush to the Root element's Visual.
_backgroundVisual = compositor.CreateSpriteVisual();
_backgroundVisual.Brush = _gradientBrush;
ElementCompositionPreview.SetElementChildVisual(Root, _backgroundVisual);
// There are 3 animations going on here.
// First, we kick off an EndPoint offset animation to create an special entrance scene.
// Once it's finished, we then kick off TWO other animations simultaneously.
// These TWO animations include a set of gradient stop color animations and
// a rotation animation that rotates the gradient brush.
var linearEase = compositor.CreateLinearEasingFunction();
var batch = compositor.CreateScopedBatch(CompositionBatchTypes.Animation);
batch.Completed += (s, e) =>
{
StartGradientColorAnimations();
StartGradientRotationAnimation();
};
var endPointOffsetAnimation = compositor.CreateVector2KeyFrameAnimation();
endPointOffsetAnimation.Duration = TimeSpan.FromSeconds(3);
endPointOffsetAnimation.InsertKeyFrame(1.0f, Vector2.One);
_gradientBrush.StartAnimation(nameof(_gradientBrush.EndPoint), endPointOffsetAnimation);
batch.End();
void StartGradientColorAnimations()
{
var color1Animation = compositor.CreateColorKeyFrameAnimation();
color1Animation.Duration = TimeSpan.FromSeconds(10);
color1Animation.IterationBehavior = AnimationIterationBehavior.Forever;
color1Animation.Direction = AnimationDirection.Alternate;
color1Animation.InsertKeyFrame(0.0f, GradientStop1StartColor, linearEase);
color1Animation.InsertKeyFrame(0.5f, Color.FromArgb(255, 65, 88, 208), linearEase);
color1Animation.InsertKeyFrame(1.0f, Color.FromArgb(255, 43, 210, 255), linearEase);
gradientStop1.StartAnimation(nameof(gradientStop1.Color), color1Animation);
var color2Animation = compositor.CreateColorKeyFrameAnimation();
color2Animation.Duration = TimeSpan.FromSeconds(10);
color2Animation.IterationBehavior = AnimationIterationBehavior.Forever;
color2Animation.Direction = AnimationDirection.Alternate;
color2Animation.InsertKeyFrame(0.0f, GradientStop2StartColor, linearEase);
color1Animation.InsertKeyFrame(0.5f, Color.FromArgb(255, 200, 80, 192), linearEase);
color2Animation.InsertKeyFrame(1.0f, Color.FromArgb(255, 43, 255, 136), linearEase);
gradientStop2.StartAnimation(nameof(gradientStop2.Color), color2Animation);
}
void StartGradientRotationAnimation()
{
var rotationAnimation = compositor.CreateScalarKeyFrameAnimation();
rotationAnimation.Duration = TimeSpan.FromSeconds(15);
rotationAnimation.IterationBehavior = AnimationIterationBehavior.Forever;
rotationAnimation.InsertKeyFrame(1.0f, 360.0f, linearEase);
_gradientBrush.StartAnimation(nameof(_gradientBrush.RotationAngleInDegrees), rotationAnimation);
}
这是一个有效的 sample,下面是它的样子。 :)