UWP wincomposition: анимация смещения нескольких изображений

Я пытаюсь анимировать несколько изображений (разного размера) в одном элементе управления Grid, но анимируется только самое большое из них. Целевое свойство — «Offset.x».

        var container = new Grid();
        var compositor = ElementCompositionPreview.GetElementVisual(container).Compositor;
        var containerVisual = compositor.CreateContainerVisual();

        // ------
        // CLOUDS
        // ------
        var cloudImage1 = CreateCloudImage(60);
        var cloudVisual1 = ElementCompositionPreview.GetElementVisual(cloudImage1);

        var cloudImage2 = CreateCloudImage(70);
        var cloudVisual2 = ElementCompositionPreview.GetElementVisual(cloudImage2);

        var cloudImage3 = CreateCloudImage(50);
        var cloudVisual3 = ElementCompositionPreview.GetElementVisual(cloudImage3);

        container.Children.Add(cloudImage1);
        container.Children.Add(cloudImage2);
        container.Children.Add(cloudImage3);

        containerVisual.Children.InsertAtTop(cloudVisual1);
        containerVisual.Children.InsertAtTop(cloudVisual2);
        containerVisual.Children.InsertAtTop(cloudVisual3);

        // ----------
        // ANIMATIONS
        // ----------
        var offsetAnimation = CreateOffsetAnimation(compositor, 50, 6);
        cloudVisual1.StartAnimation("Offset.x", offsetAnimation);

        offsetAnimation.InsertKeyFrame(1f, -60);
        cloudVisual2.StartAnimation("Offset.x", offsetAnimation); // doesn't work

        ElementCompositionPreview.SetElementChildVisual(container, containerVisual);

        return container;

Вспомогательные методы:

static ScalarKeyFrameAnimation CreateOffsetAnimation(Compositor compositor, float endKeyFrame, double duration) {
        var animation = compositor.CreateScalarKeyFrameAnimation();
        animation.InsertKeyFrame(0f, 0);
        animation.InsertKeyFrame(1f, endKeyFrame);
        animation.IterationBehavior = AnimationIterationBehavior.Forever;
        animation.Direction = AnimationDirection.Alternate;
        animation.Duration = TimeSpan.FromSeconds(duration);

        return animation;
}

static Image CreateCloudImage(double size) {
       var cloudBitmapImage = new BitmapImage(new Uri("ms-appx:///Assets/Icons/cloudy.png"));
       var cloudImageControl = new Image() {
            Source = cloudBitmapImage,
            Height = size,
            Width = size,
       };

       return cloudImageControl;
}

Обратите внимание, что если я сделаю второе изображение самым большим, оно станет анимированным.

Любая идея о том, как решить эту проблему?

Заранее спасибо.


person rootasjey    schedule 16.07.2017    source источник


Ответы (1)


Короткий ответ: используйте элемент управления Canvas для хранения изображений.

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

Чтобы решить эту проблему, я добавил элемент управления Canvas для хранения изображений и добавил этот Canvas в качестве дочернего элемента контейнера Grid.

        var container = new Grid();
        var compositor = ElementCompositionPreview.GetElementVisual(container).Compositor;
        var containerVisual = compositor.CreateContainerVisual();

        var canvas = new Canvas();

        // ------
        // CLOUDS
        // ------
        var cloudImage1 = CreateCloudImage(60);
        var cloudVisual1 = ElementCompositionPreview.GetElementVisual(cloudImage1);

        var cloudImage2 = CreateCloudImage(70);
        var cloudVisual2 = ElementCompositionPreview.GetElementVisual(cloudImage2);

        var cloudImage3 = CreateCloudImage(50);
        var cloudVisual3 = ElementCompositionPreview.GetElementVisual(cloudImage3);

        canvas.Children.Add(cloudImage1);
        canvas.Children.Add(cloudImage2);
        canvas.Children.Add(cloudImage3);

        containerVisual.Children.InsertAtTop(cloudVisual1);
        containerVisual.Children.InsertAtTop(cloudVisual2);
        containerVisual.Children.InsertAtTop(cloudVisual3);

        // ----------
        // ANIMATIONS
        // ----------
        var offsetAnimation = CreateOffsetAnimation(compositor, 50, 6);
        cloudVisual1.StartAnimation("Offset.x", offsetAnimation);

        offsetAnimation.InsertKeyFrame(1f, -60);
        cloudVisual2.StartAnimation("Offset.x", offsetAnimation); // work

        offsetAnimation.InsertKeyFrame(1f, 100);
        cloudVisual3.StartAnimation("Offset.x", offsetAnimation); // work

        ElementCompositionPreview.SetElementChildVisual(canvas, containerVisual);

        container.Children.Add(canvas);
        return container;

(Замена контейнера Grid контейнером Canvas тоже должна работать).

person rootasjey    schedule 16.07.2017
comment
Это действительно вызвано Решеткой. Причина объясняется здесь. Вы можете обернуть каждое изображение границей без использования холста. В обновлении Creators вы можете анимировать свойство Translation вместо Offset. Ознакомьтесь с методом StartTranslationAnimation из здесь. - person Justin XL; 17.07.2017
comment
Благодарю вас! Я собираюсь изучить это :) - person rootasjey; 23.07.2017