Гладкое взаимодействие и движения в визуальном слое UWP приложений

API композиции поставляются с надёжным движком анимации, который обеспечивает быстрое и непрерывное выполнение движения в отдельном процессе приложения универсальной платформы Windows (UWP). Это обеспечивает последовательное отображение без пропусков 60 кадров в секунду при запуске приложения и на IoT устройствах, а также на игровой приставке. Это довольно просто и быстро.

API композиции также обеспечивают то, к чему вы, вероятно, никогда не имели доступа ранее: возможность создавать высокопроизводительные, низкоуровневые манипуляции с пользовательской анимацией, как показано выше. Предварительные релизы API композиции уже дали вам возможность управлять анимацией с помощью свойства ManipulationPropertySet для ScrollViewer в XAML. Юбилейное обновление Windows 10 Anniversary Update позволяет пойти еще дальше, с целью расширения возможностей разработчиков для использования множества типов управления анимацией.

В этой публикации мы кратко рассмотрим основы использования анимации с помощью выражений. Дальше мы будем двигаться к демонстрации того, как управлять анимацией с помощью выражений из ScrollViewer ManipulationPropertySet, и более важно, почему вам действительно это должно быть интересно, даже если вы ещё не поняли как это работает. И, наконец, мы коснёмся InteractionTracker и дадим представление о том, насколько более мощные возможности сегодня у вас, как у разработчика, чем были в конце июля.

Быстрый обзор анимации с помощью выражений
Визуальный слой поддерживает анимацию по ключевым кадрам, так и анимацию с помощью выражений. Если вы работали с XAML анимацией раньше, то вы, вероятно, уже знакомы с тем, как работает анимация с помощью ключевых кадров. В анимации по ключевым кадрам вы устанавливаете значения для некоторых свойств, которые вы хотите изменить в течение определенного промежутка времени, а также назначаете длительность этого изменения: в приведенном ниже примере установлены начальное значение, промежуточное значения, а затем конечное значение. Система анимации будет заботиться о промежуточных кадрах анимации – другими словами, будут сгенерированы все промежуточные значения между теми, которые вы явно указали.

  1. ScalarKeyFrameAnimation blurAnimation = _compositor.CreateScalarKeyFrameAnimation();
  2. blurAnimation.InsertKeyFrame(0.0f, 0.0f);
  3. blurAnimation.InsertKeyFrame(0.5f, 100.0f);
  4. blurAnimation.InsertKeyFrame(1.0f, 0.0f);
  5. blurAnimation.Duration = TimeSpan.FromSeconds(4);
  6. blurAnimation.IterationBehavior = AnimationIterationBehavior.Forever;
  7. _brush.StartAnimation(«Blur.BlurAmount», blurAnimation);

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

В демонстрационном примере выше (исходный код), каждая серая шестерня анимирована на основе анимации шестерни, с которой она зацепляется и стоит перед ней. Если предыдущая шестерня внезапно начинает вращаться быстрее или меняет направление вращения, она заставляет следующую шестерню сделать то же самое. Анимации по ключевым кадрам не может создавать эффекты движения, которые работают таким образом, а анимация с помощью выражений может. Такая разница потому, что анимация с помощью ключевых кадров основывается на времени, а анимация с помощью выражений основывается на ссылках.
Критический код, который перехватывает состояние шестерни для анимации в демонстрационном примере можно найти в следующем разделе, который вызывает метод CreateExpressionAnimation для экземпляра Compositor. Выражение в основном говорит о том, что анимация должна ссылаться и приводиться в свойстве RotationAngleInDegrees визуального состояния, указанного в параметре «previousGear». В следующей строке назначается опорный параметр. В последней строке, свойство визуального состояния RotationAngleInDegrees окончательно получает анимацию на основе значения, указанного в объекте ExpressionAnimation.

  1. private void ConfigureGearAnimation(Visual currentGear, Visual previousGear)
  2. {
  3.     // If rotation expression is null then create an expression of a gear rotating the opposite direction
  4.     _rotationExpression = _rotationExpression ?? _compositor.CreateExpressionAnimation(«-previousGear.RotationAngleInDegrees»);
  5.     // put in placeholder parameters
  6.     _rotationExpression.SetReferenceParameter(«previousGear», previousGear);
  7.     // Start the animation based on the Rotation Angle in Degrees.
  8.     currentGear.StartAnimation(«RotationAngleInDegrees», _rotationExpression);
  9. }

Но если анимация может управляться другой анимацией, вам должно быть интересно можем ли мы также управлять анимацией с чем-то более конкретным, например с помощью вводимых пользователем данных? Да, можем!

Красота набора ManipulationPropertySet для ScrollViewer
Управление анимацией из ScrollViewer с помощью взаимодействия XAML-композицией достаточно легкое. С помощью всего лишь нескольких строк кода вы можете добавить анимацию к ранее существовавшему элементу управления ScrollViewer, воспользовавшись методом GetScrollViewerManipulationPropertySet класса ElementCompositionPreview.
Вы могли бы использовать эту технику если вы хотите, чтобы добавить эффект параллакса к вашему XAML или создать закрепленный заголовок, который остается на месте в то время, как контент прокручивается под ним. В демонстрационном примере, показанном ниже (исходный код), ScrollViewer используется для управления эффектом параллакса на ListView.

Добавление поведения с эффектом параллакса на страницу XAML может быть выполнено всего в несколько строк, как в следующем примере кода, который демонстрирует Джеймс Кларк.

  1. CompositionPropertySet scrollerManipProps = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(myScroller);
  2. Compositor compositor = scrollerManipProps.Compositor;
  3. // Create the expression
  4. ExpressionAnimation expression = compositor.CreateExpressionAnimation(«scroller.Translation.Y * parallaxFactor»);
  5. // wire the ParallaxMultiplier constant into the expression
  6. expression.SetScalarParameter(«parallaxFactor», 0.3f);
  7. // set «dynamic» reference parameter that will be used to evaluate the current position of the scrollbar every frame
  8. expression.SetReferenceParameter(«scroller», scrollerManipProps);
  9. // Get the background image and start animating it’s offset using the expression
  10. Visual backgroundVisual = ElementCompositionPreview.GetElementVisual(background);
  11. backgroundVisual.StartAnimation(«Offset.Y», expression);

Ещё более прекрасный InteractionTracker
Управление анимацией с помощью выражений над элементом ScrollViewer является чрезвычайно мощным, но что, если вы вместо этого хотите управлять анимацией с помощью жестов? Что делать, если вы хотите, чтобы элементы можно было притянуть с помощью ваших пальцев как показано в демонстрационном примере ниже (исходный код) или анимировать несколько пролетающих изображений по горизонтали экрана, как это происходит в демонстрационном примере в самом начале этой публикации (исходный код)?

Для достижения этих эффектов, вы бы использовали новые классы InteractionTracker и VisualInteractionSource. InteractionTracker является конечным автоматом, который может приводиться в действие от ваших активных входных данных. Это то, что вы подключите к вашей анимации. Класс VisualInteractionSource, с другой стороны, определяет, какой вход вы будете использовать, чтобы управлять вашим InteractionTracker.

Следующий пример кода демонстрирует основную реализацию InteractionTracker, который приводится в движение с помощью сенсорного ввода. viewportVisual является просто поддержкой визуального состояния для корневого элемента на странице. Вы можете использовать это как VisualInteractionSource для трекера. При этом вы указываете, что вы отслеживаете манипуляции по Х и Y. Вы также можете указать, что вы хотите отслеживать относительное движение.

  1. _tracker = InteractionTracker.Create(_compositor);
  2. var interactionSource = VisualInteractionSource.Create(viewportVisual);
  3. interactionSource.PositionXSourceMode = InteractionSourceMode.EnabledWithInertia;
  4. interactionSource.PositionYSourceMode = InteractionSourceMode.EnabledWithInertia;
  5. _tracker.InteractionSources.Add(interactionSource);

Подключение трекера к анимации с помощью выражений работает в основном также, как подключение визуального состояния одной шестерни к визуальному состоянию другой шестерни, как вы делали в примере выше. Вызовите метод фабрики CreateExpressionAnimation для текущего компоновщика Compositor и сошлитесь на свойство Position трекера. Затем вы можете анимировать свойство Offset визуальной составляющей, если вы хотите добавить движение к вашему выражению.

  1. var positionExpression = _compositor.CreateExpressionAnimation(«-tracker.Position»);
  2. positionExpression.SetReferenceParameter(«tracker», _tracker);
  3. contentVisual.StartAnimation(«Offset», positionExpression);

Таковы основы управления анимацией из практически любых входных данных. Что вы сделаете с этой удивительной новой силой, полностью зависит от вас.

Подводя итоги
Анимации с помощью выражений и взаимодействия в визуальном слое — это тема, в которую можно погрузиться очень глубоко и очень быстро. Чтобы помочь вам в этом погружении, мы настоятельно рекомендуем следующие видео и статьи:
Удовольствие от использования выражений в анимациях
Использование анимаций с помощью выражений для создания эффектных и настроенных под ваши нужды пользовательских интерфейсов
Добавление взаимодействий в визуальном слое для создания настраиваемого и отзывчивого опыта взаимодействия
Визуальный слой — захват экрана блокировки

Перевод оригинальной публикации Smooth Interaction and Motion with the Visual Layer
Автор: Michael Crump
Перевод: Сергей Урусов

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *