Creare punti di ancoraggio con modificatori di inerzia

In questo articolo viene illustrato in modo più approfondito come usare la funzionalità InertiaModifier di InteractionTracker per creare esperienze di movimento agganciabili a un punto specificato.

Prerequisiti

In questo caso si presuppone che si abbia familiarità con i concetti illustrati in questi articoli:

Quali sono i punti di ancoraggio e perché sono utili?

Quando si creano esperienze di manipolazione personalizzate, a volte è utile creare punti di posizione specializzati all'interno dell'area di disegno scorrevole/zoomabile in cui InteractionTracker verrà sempre riposato. Questi sono spesso chiamati punti di ancoraggio.

Si noti nell'esempio seguente come lo scorrimento può lasciare l'interfaccia utente in posizione scomoda tra le diverse immagini:

Scorrimento senza punti di ancoraggio

Se si aggiungono punti di ancoraggio, quando si interrompe lo scorrimento tra le immagini, questo rimane "agganciato" a una posizione specificata. Con i punti di ancoraggio l'esperienza di scorrimento delle immagini diventa più pulita e più reattiva.

Scorrimento con un singolo punto di ancoraggio

InteractionTracker e InertiaModifier

Quando si creano esperienze di manipolazione personalizzate con InteractionTracker, è possibile creare esperienze di movimento dei punti di ancoraggio usando InertiaModifier. Gli InertiaModifier sono essenzialmente un modo per definire dove o come InteractionTracker raggiunge la destinazione quando entra nello stato inerzia. È possibile applicare InertiaModifier per influire sulla posizione X o Y o sulle proprietà Scale di InteractionTracker.

Esistono 3 tipi di InertiaModifier:

  • InteractionTrackerInertiaRestingValue: un modo per modificare la posizione di riposo finale dopo un'interazione o una velocità programmatica. Un movimento predefinito porterà InteractionTracker a tale posizione.
  • InteractionTrackerInertiaMotion: un modo per definire un interactionTracker di movimento specifico verrà eseguito dopo un'interazione o una velocità programmatica. La posizione finale sarà derivata da questo movimento.
  • InteractionTrackerInertiaNaturalMotion: un modo per definire la posizione finale di riposo dopo un'interazione o una velocità programmatica, ma con un'animazione basata sulla fisica (NaturalMotionAnimation).

Quando si immette l'inerzia, InteractionTracker valuta ogni InertiaModifier assegnato e determina se uno di essi si applica. Ciò significa che è possibile creare e assegnare più InertiaModifier a un InteractionTracker, ma, quando vengono definiti è necessario eseguire le operazioni seguenti:

  1. Definire la condizione: Expression che definisce l'istruzione condizionale quando deve essere eseguito questo specifico InertiaModifier. Spesso richiede l'analisi di NaturalRestingPosition di InteractionTracker (destinazione data l'inerzia predefinita).
  2. Definire RestingValue/Motion/NaturalMotion: definire l'Expression valore di riposo effettiva, l'Expression movimento o NaturalMotionAnimation che viene eseguita quando viene soddisfatta la condizione.

Nota

L'aspetto della condizione degli InertiaModifier viene valutato una sola volta quando InteractionTracker entra in inerzia. Tuttavia, solo per InertiaMotion, l'Expression di movimento viene valutata ogni fotogramma per il modificatore la cui condizione è vera.

Esempio

Si esaminerà ora come usare InertiaModifier per creare alcune esperienze di punto di ancoraggio per ricreare l'area di disegno di scorrimento delle immagini. In questo esempio, ogni manipolazione è destinata a spostarsi potenzialmente attraverso una singola immagine, usando punti di ancoraggio obbligatori singoli.

Per iniziare, configurare InteractionTracker, VisualInteractionSource e Expression che userà la posizione di 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);
}

Successivamente, poiché un singolo comportamento di punto di ancoraggio obbligatorio sposta il contenuto verso l'alto o verso il basso, saranno necessari due modificatori di inerzia diversi: uno che sposta il contenuto scorrevole verso l'alto e uno che lo sposta verso il basso.

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

L'allineamento verso l'alto o verso il basso viene determinato in base alla posizione in cui InteractionTracker atterrerebbe naturalmente all'interno della distanza di ancoraggio, ovvero la distanza tra le posizioni di ancoraggio. Se supera il punto intermedio, si blocca verso il basso; in caso contrario, si blocca verso l'alto. In questo esempio si archivia la distanza di ancoraggio in un oggetto 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);

Questo diagramma fornisce una descrizione visiva alla logica in corso:

Diagramma del modificatore di inerzia

A questo punto è sufficiente definire i valori di riposo per ogni InertiaModifier: spostare la posizione di InteractionTracker nella posizione di ancoraggio precedente o in quella successiva.

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

Infine, aggiungere InertiaModifier a InteractionTracker. Ora, quando InteractionTracker entra in InertiaState, controlla le condizioni degli InertiaModifier per verificare se la posizione deve essere modificata.

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