Posted on 8. July 2017

Взаимодействие и Движение с Visual Layer in Windows 10 Creators Update

https://blogs.windows.com/buildingapps/2017/06/27/smooth-interaction-motion-visual-layer-windows-10-creators-update/amp/

API-интерфейс Composition оснащен мощным механизмом анимации, который обеспечивает быстрое движение, выполняемое в отдельном процессе вашего UWP приложения. Это гарантирует постоянство 60 кадров в секунду при запуске вашего приложения на устройстве IoT, а также на игровых девайсах. Это просто и очень быстро! Это необходимая возможность для внедрения Fluent Design System, которая сподвигла Microsoft создавать ощущение кинематографического движения в UWP приложениях.

 

 

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

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

Быстрая и подвижная анимационная система

Visual Layer поддерживает анимацию как для ключевого кадра, так и для анимации выражений. Если вы раньше работали с анимацией XAML, вы, вероятно, уже знакомы с тем, как работают ключевые кадры. В анимации ключевого кадра вы устанавливаете значения для некоторого свойства, которое со временем хотите изменить, а также необходимо назначить продолжительность для изменения: в приведенном ниже примере начальное значение, среднее значение, а затем конечное значение. Система анимации будет следить за анимацией - другими словами, создавая все значения между теми, которые вы явно указали, на основе выбранной функции. Linear или Cubic Bezier -  система анимации будет использовать это для определения значений при интерполяции.

 

CubicBezierEasingFunction cubicBezier = _compositor.CreateCubicBezierEasingFunction(new Vector2(.17f, .67f), new Vector2(1f, 1f));
ScalarKeyFrameAnimation blurAnimation = _compositor.CreateScalarKeyFrameAnimation();
blurAnimation.InsertKeyFrame(0.0f, 0.0f);
blurAnimation.InsertKeyFrame(0.5f, 100.0f);
blurAnimation.InsertKeyFrame(1.0f, 0.0f);
blurAnimation.Duration = TimeSpan.FromSeconds(4);
blurAnimation.IterationBehavior = AnimationIterationBehavior.Forever;
_brush.StartAnimation("Blur.BlurAmount", blurAnimation);

 

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

 

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

Решающий код, который подключает шестерни для анимации, находится в следующем примере кода, который использует новую Expression Builder Library - компонент с открытым исходным кодом, выпущенный в Creators Update для создания анимаций выражений. Вышеприведенное выражение говорит о том, что анимация должна ссылаться и управляться свойством RotationAngleInDegrees Visual, которое обозначается параметром «previousGear». В следующей строке текущее свойство RotationAngleInDegrees Visual в конечном итоге анимируется на основе значения, указанного в выражении.

 

private void ConfigureGearAnimation(Visual currentGear, Visual previousGear)
{
    // If rotation expression is null then create an expression of a gear rotating the opposite direction

    var _rotateExpression = previousGear.GetReference().RotationAngleInDegrees;

    // Start the animation based on the Rotation Angle in Degrees.
    currentGear.StartAnimation("RotationAngleInDegrees", _rotateExpression);
}

 

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

Великолепие ScrollViewer ManipulationPropertySet

Управлять анимацией из ScrollViewer с помощью XAML-Composition interop довольно просто. При наличие всего несколько строк кода, вы можете улучшить визуализацию существующего элемента управления ScrollViewer с помощью CompositionAnimation, используя метод GetScrollViewerManipulationPropertySet в классе ElementCompositionPreview. Используя выражение анимации, вы можете привязать свою анимацию к позиции вашего компонента ScrollViewer.

 

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

 

Добавление смещения на страницу XAML может быть выполнено с помощью нескольких строк.

 

// Note: We're not using the ScrollViewer's offset values directly. Instead, we use this PropertySet which holds the position values of the ScrollViewer in real-time.
var scrollPropSet = _scrollProperties.GetSpecializedReference();
var startOffset = ExpressionValues.Constant.CreateConstantScalar("startOffset", 0.0f);
var parallaxValue = 0.5f;
var itemHeight = 0.0f;
var parallax = (scrollPropSet.Translation.Y + startOffset - (0.5f * itemHeight));
_parallaxExpression = parallax * parallaxValue - parallax;
_parallaxExpression.SetScalarParameter("StartOffset", (float)args.ItemIndex * visual.Size.Y / 4.0f);
visual.StartAnimation("Offset.Y", _parallaxExpression);

 

 

Еще больше красоты в InteractionTracker

Управление анимацией выражений с помощью ScrollViewer чрезвычайно мощное, но что делать, если вы хотите управлять анимацией с помощью сенсорных жестов, которые не ограничиваются жестом панорамирования / увеличения? Кроме того, при использовании манипуляций ScrollViewer ваши анимации связаны с реагированием на поток пользовательского интерфейса и могут потерять это ощущение, когда поток пользовательского интерфейса увязнет.

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

 

Чтобы достичь этих эффектов, вы должны использовать новые классы InteractionTracker и VisualInteractionSource. InteractionTracker - это конечный инструмент, который может управляться активным входом. InteractionTracker также поддерживает ряд свойств, таких как Position и ScalePosition, как часть поддержания состояния. Это то, что вы подключаете к анимации. С другой стороны, класс VisualInteractionSource определяет, какой вход вы будете использовать для вождения вашего InteractionTracker, а также когда начинаете обработку ввода (в частности сенсорное).

 

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

 

_tracker = InteractionTracker.Create(_compositor);

var interactionSource = VisualInteractionSource.Create(viewportVisual);

interactionSource.PositionXSourceMode = InteractionSourceMode.EnabledWithInertia;
interactionSource.PositionYSourceMode = InteractionSourceMode.EnabledWithInertia;

_tracker.InteractionSources.Add(interactionSource);

 

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

 

ar positionExpression = _compositor.CreateExpressionAnimation("-tracker.Position");
positionExpression.SetReferenceParameter("tracker", _tracker);

contentVisual.StartAnimation("Offset", positionExpression);

 

Этот код использует позицию InteractionTracker для создания бесперебойной анимации для смещения Visual. Вы также можете включить анимацию Blur и Opacity для других визуальных эффектов. Это приведет к тому, что все три анимации будут работать вместе, со значениями, основанными на том, как далеко пользователь перетащит палец, чтобы получить удивительно подвижный визуальный эффект. Запустите демо-версию и попробуйте (исходный код).

Это основы управления любой анимацией с любого входа. Все действия будут зависеть от вас.

В завершение

Экспрессионные анимации и взаимодействия с визуальным слоем - это темы, которые быстро набирают спрос. Для подробного ознакомления, мы рекомендуем следующие видеоролики и статьи: