Поделиться через


Создание точек фиксации с модификаторами инерции

В этой статье мы углубленно рассмотрим, как использовать функцию "Инерционный модификатор" элемента InteractionTracker для создания анимаций, которые привязываются к заданной точке в приложении WinUI.

В приложениях WinUI типы модификаторов инерции и связанные с ними элементы находятся в пространстве имен Microsoft.UI.Composition.Interactions.

Необходимые условия

Здесь предполагается, что вы знакомы с понятиями, описанными в следующих статьях:

Что такое точки привязки и почему они полезны?

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

Обратите внимание, что в следующем примере прокрутка может оставить пользовательский интерфейс в неловком положении между различными изображениями:

Прокрутка без точек привязки

При добавлении точек привязки, при остановке прокрутки между изображениями они "фиксируются" в указанном положении. С точками привязки прокрутка изображений становится значительно более точной и отзывчивой.

Прокрутка с одной точкой остановки

InteractionTracker и Инерционные модификаторы

При создании настраиваемых взаимодействий с помощью InteractionTracker можно создавать опыт движения точек привязки, используя модификаторы инерции. Инерционные модификаторы — это способ определения того, где или как InteractionTracker достигает своей цели при вхождении в состояние инерции. Можно применить инерционные модификаторы, чтобы повлиять на положение X или Y или свойства Scale объекта InteractionTracker.

Существует 3 типа инерционных модификаторов:

  • InteractionTrackerInertiaRestingValue — способ изменить конечное положение состояния покоя после взаимодействия или заданной скорости. Предопределенное движение переместит InteractionTracker в указанное положение.
  • InteractionTrackerInertiaMotion — способ описания конкретного движения, которое InteractionTracker будет выполнять после взаимодействия или программного ускорения. Окончательное положение будет производным от этого движения.
  • InteractionTrackerInertiaNaturalMotion — способ определить окончательную позицию отдыха после взаимодействия или программной скорости, но с анимацией на основе физики (NaturalMotionAnimation).

При переходе в фазу инерции InteractionTracker оценивает каждый из назначенных ему модификаторов инерции и определяет, применяются ли какие-либо из них. Это означает, что вы можете создать и назначить несколько модификаторов инерции с объектом InteractionTracker. Но при определении каждого необходимо сделать следующее:

  1. Определите условие — выражение, определяющее условное выражение, когда следует применять этот конкретный инерционный модификатор. Для этого часто требуется взглянуть на параметр NaturalRestingPosition в InteractionTracker (целевое значение с учетом инерции по умолчанию).
  2. Определите RestingValue/Motion/NaturalMotion — укажите истинное выражение Resting Value, выражение движения или NaturalMotionAnimation, которое используется при выполнении условия.

Замечание

Аспект условий InertiaModifiers оценивается только один раз, когда InteractionTracker переходит в состояние инерции. Однако только для InertiaMotion выражение движения вычисляется для модификатора, условие которого верно, в каждом кадре.

Пример

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

Начнем с настройки InteractionTracker, VisualInteractionSource и создания выражения, которое будет использовать позицию InteractionTracker.

private void SetupInput()
{
    _tracker = InteractionTracker.Create(_compositor);
    _tracker.MinPosition = new Vector3(0f);
    _tracker.MaxPosition = new Vector3(3000f);

    _source = VisualInteractionSource.Create(_root);
    _source.ManipulationRedirectionMode =
        VisualInteractionSourceRedirectionMode.CapableTouchpadOnly;
    _source.PositionYSourceMode = InteractionSourceMode.EnabledWithInertia;
    _tracker.InteractionSources.Add(_source);

    var scrollExp = _compositor.CreateExpressionAnimation("-tracker.Position.Y");
    scrollExp.SetReferenceParameter("tracker", _tracker);
    ElementCompositionPreview.GetElementVisual(scrollPanel).StartAnimation("Offset.Y", scrollExp);
}

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

// Snap-Point to move the content up
var snapUpModifier = InteractionTrackerInertiaRestingValue.Create(_compositor);
// Snap-Point to move the content down
var snapDownModifier = InteractionTrackerInertiaRestingValue.Create(_compositor);

Определение того, следует ли привязывать вверх или вниз, основано на том, где InteractionTracker естественным образом остановится относительно расстояния привязки — расстояния между точками привязки. Если прошло полпути, то оформите вниз, в противном случае оформите вверх. (В этом примере вы сохраняете расстояние привязки в PropertySet)

// Is NaturalRestingPosition less than the halfway point between Snap Points?
snapUpModifier.Condition = _compositor.CreateExpressionAnimation(
"this.Target.NaturalRestingPosition.y < (this.StartingValue - " + 
"mod(this.StartingValue, prop.snapDistance) + prop.snapDistance / 2)");
snapUpModifier.Condition.SetReferenceParameter("prop", _propSet);
// Is NaturalRestingPosition greater than the halfway point between Snap Points?
snapDownModifier.Condition = _compositor.CreateExpressionAnimation(
"this.Target.NaturalRestingPosition.y >= (this.StartingValue - " + 
"mod(this.StartingValue, prop.snapDistance) + prop.snapDistance / 2)");
snapDownModifier.Condition.SetReferenceParameter("prop", _propSet);

Эта схема содержит визуальное описание логики, которая происходит:

Схема модификатора инерции

Теперь просто необходимо определить значения покоя для каждого InertiaModifier: переместите позицию InteractionTracker на предыдущую или следующую позицию фиксации.

snapUpModifier.RestingValue = _compositor.CreateExpressionAnimation(
"this.StartingValue - mod(this.StartingValue, prop.snapDistance)");
snapUpModifier.RestingValue.SetReferenceParameter("prop", _propSet);
snapDownModifier.RestingValue = _compositor.CreateExpressionAnimation(
"this.StartingValue + prop.snapDistance - mod(this.StartingValue, " + 
"prop.snapDistance)");
snapDownModifier.RestingValue.SetReferenceParameter("prop", _propSet);

Наконец, добавьте модификаторы инерции в InteractionTracker. Теперь, когда InteractionTracker входит в состояние инерции, он проверяет условия инерционных модификаторов, чтобы определить, следует ли изменить его положение.

var modifiers = new InteractionTrackerInertiaRestingValue[] { 
snapUpModifier, snapDownModifier };
_tracker.ConfigurePositionYInertiaModifiers(modifiers);