Цветная анимация с легкостью

Я следил за этим вопросом, чтобы сделать цвет анимация.

Я могу создать анимацию, и она работает нормально, пока анимация не запустится снова. Есть момент, когда кажется, что анимация была запущена/остановлена ​​на мгновение. Я хочу, чтобы анимация работала гладко, чтобы в цветах не отображались эффекты перезапуска. Возможно ли это сделать?

Я использую следующий код:

        <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();

Может быть, есть какой-то метод «замедления», который смешивает начало и конец анимации, чтобы она выглядела плавной, как длинная анимация. Какие-либо предложения?


person Ahmar    schedule 18.08.2017    source источник
comment
Я думаю, что вам просто нужно закончить в том же состоянии, в котором вы начали. Так что это может быть просто Красный -> Черный -> Красный. Разве это не работает?   -  person michauzo    schedule 18.08.2017
comment
Что ты имеешь в виду под "начать заново"? Разве это не работает вечно? Вы вручную останавливаете и перезапускаете его?   -  person Justin XL    schedule 19.08.2017
comment
Да, он работал вечно, но работал не так гладко, как должно было быть, потому что был своего рода «пробел».   -  person Ahmar    schedule 20.08.2017


Ответы (1)


Вы можете попробовать EasingColorKeyFrame, но анимация никогда не будет гладкой, потому что она выполняется в потоке пользовательского интерфейса (то есть EnableDependentAnimation="True").

Вот некоторые хорошие и плохие новости. Хорошо, что теперь у нас есть новый API градиентной кисти на уровне слоя Composition, что означает, что он полностью анимируется и работает вне потока пользовательского интерфейса. Так что с точки зрения производительности это будет намного лучше, чем текущее решение Storyboard. Но он доступен только в Windows 10 Insider Preview 16225 и более поздних версиях, что означает, что он не будет работать для большинства ваших текущих пользователей, кроме инсайдеров.

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

Обратите внимание, что я добавил немного соуса в анимацию, чтобы сделать ее более интересной. Если вы хотите, чтобы анимировались только цвета, не стесняйтесь перемещать анимации 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);
}

Вот работающий образец, и вот как он выглядит. :)

введите описание изображения здесь

person Justin XL    schedule 19.08.2017
comment
В моем первоначальном вопросе мне нужно было только удалить BeginTime из анимации, чтобы сделать ее плавной. Но я очень ценю усилия. - person Ahmar; 20.08.2017