Compartir a través de


Creación de puntos de acoplamiento con modificadores de inercia

En este artículo, se profundiza en cómo usar la característica InteractionTracker InertiaModifier para crear experiencias de movimiento que se ajusten a un punto especificado en una aplicación WinUI.

En las aplicaciones WinUI, InteractionTracker y los tipos de modificadores de inercia relacionados se encuentran en el Microsoft.UI.Composition.Interactions espacio de nombres.

Prerrequisitos

Aquí se supone que está familiarizado con los conceptos descritos en estos artículos:

¿Qué son los puntos de acoplamiento y por qué son útiles?

Al crear experiencias de manipulación personalizadas, a veces resulta útil crear puntos de posición especializados dentro del lienzo desplazable o zoomable en el que InteractionTracker siempre descansará. A menudo se denominan puntos de acoplamiento.

Observe en el ejemplo siguiente cómo el desplazamiento puede dejar la interfaz de usuario en una posición torpe entre las distintas imágenes:

Desplazamiento sin puntos de acoplamiento

Si agrega puntos de ajuste, al cesar de desplazarse entre las imágenes, estas se "acoplan" a una posición especificada. Con puntos de ajuste, la experiencia de desplazarse por imágenes se vuelve mucho más limpia y más responsiva.

Desplazamiento con un único punto de acoplamiento

RastreadorDeInteracción y ModificadoresDeInercia

Al crear experiencias de manipulación personalizadas con InteractionTracker, es posible crear experiencias de movimiento anclado mediante modificadores de inercia. Los InertiaModifiers son esencialmente una forma de definir dónde o cómo el InteractionTracker alcanza su destino al entrar en el estado de inercia. Puede aplicar InertiaModifiers para influir en las propiedades X, Y o de escala de InteractionTracker.

Hay 3 tipos de Modificadores de Inercia:

  • InteractionTrackerInertiaRestingValue: una manera de modificar la posición de reposo final después de una interacción o velocidad programática. Un movimiento predefinido tomará InteractionTracker a esa posición.
  • InteractionTrackerInertiaMotion – una forma de definir un movimiento específico que InteractionTracker realizará después de una interacción o una velocidad programática. La posición final se derivará de este movimiento.
  • InteractionTrackerInertiaNaturalMotion: una manera de definir la posición de reposo final después de una interacción o velocidad programática, pero con una animación basada en física (NaturalMotionAnimation).

Al entrar en Inercia, InteractionTracker evalúa cada uno de los modificadores de inercia asignados a este y determina si alguno de ellos se aplica. Esto significa que se pueden crear y asignar varios InertiaModifiers a un InteractionTracker. Pero, al definir cada uno, debe hacer lo siguiente:

  1. Definir la condición: una expresión que define la instrucción condicional en la que debe aplicarse este InertiaModifier específico. Esto a menudo requiere examinar la posición natural de reposo de InteractionTracker (con el destino dado la inercia predeterminada).
  2. Definir RestingValue/Motion/NaturalMotion: Defina la expresión de valor en reposo, la expresión de movimiento o la animación de movimiento natural que tiene lugar cuando se cumple la condición.

Nota:

El aspecto de condición de los InertiaModifiers solo se evalúa una vez cuando InteractionTracker entra en Inercia. Sin embargo, solo para InertiaMotion, la expresión de movimiento se evalúa cada fotograma del modificador cuya condición es verdadera.

Ejemplo

Ahora echemos un vistazo a cómo puede usar InertiaModifiers para crear algunas experiencias de puntos de ajuste para volver a crear la pizarra deslizante de las imágenes. En este ejemplo, cada manipulación está diseñada para desplazarse potencialmente a través de una sola imagen; esto se conoce a menudo como Single Mandatory Snap Points.

Comencemos configurando InteractionTracker, VisualInteractionSource y la expresión que aprovecharán la posición de 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);
}

A continuación, dado que un solo comportamiento de punto de acoplamiento obligatorio moverá el contenido hacia arriba o hacia abajo, necesitará dos modificadores de inercia diferentes: uno que mueva el contenido desplazable hacia arriba y otro que lo mueva hacia abajo.

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

Se determina si se debe fijar hacia arriba o hacia abajo en función de dónde InteractionTracker aterrizaría naturalmente en relación con la distancia de fijación: la distancia entre las ubicaciones de fijación. Si ha pasado el punto medio, baje rápidamente, de lo contrario, suba rápidamente. (En este ejemplo, se almacena la distancia de ajuste en un 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);

Este diagrama proporciona una descripción visual a la lógica que está ocurriendo:

Diagrama modificador de inercia

Ahora solo tiene que definir los valores de reposo para cada InertiaModifier: puede mover la posición de InteractionTracker a la posición de anclaje previa o la siguiente.

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

Por último, agregue los InertiaModifiers a InteractionTracker. Ahora, cuando InteractionTracker entra en su InertiaState, comprobará las condiciones de tus InertiaModifiers para ver si se debe modificar su posición.

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