Udostępnij za pośrednictwem


Tworzenie punktów zatrzymania za pomocą modyfikatorów inercji

W tym artykule dowiesz się, jak używać funkcji InertiaModifier usługi InteractionTracker w celu tworzenia środowisk ruchu przyciągających do określonego punktu w aplikacji WinUI.

W aplikacjach WinUI InteractionTracker powiązane typy modyfikatora inercji znajdują się w przestrzeni nazw Microsoft.UI.Composition.Interactions.

Wymagania wstępne

W tym miejscu przyjęto założenie, że znasz pojęcia omówione w następujących artykułach:

Co to są punkty zatrzaskowe i dlaczego są przydatne?

Podczas tworzenia niestandardowych środowisk manipulowania czasami warto utworzyć wyspecjalizowane punkty położenia w kanwie z możliwością przewijania/powiększania, w której zawsze będzie się znajdować funkcja InteractionTracker. Są one często nazywane punktami przyciągania.

Zwróć uwagę na to, że w poniższym przykładzie przewijanie może pozostawić interfejs użytkownika w niezręcznej pozycji między różnymi obrazami:

Przewijanie bez punktów przyciągania

Jeśli dodasz punkty przyciągania, po zatrzymaniu przewijania między obrazami, zostaną one "przyciągnięte" do określonej pozycji. Punkty przyciągania sprawiają, że doświadczenie przewijania obrazów jest znacznie czystsze i bardziej responsywne.

Przewijanie za pomocą pojedynczego punktu zaczepienia

InteractionTracker oraz InertiaModifiers

Podczas tworzenia dostosowanych doświadczeń manipulacji za pomocą InteractionTracker można tworzyć doświadczenia ruchu punktów zaczepienia, korzystając z InertiaModifiers. InertiaModifiers są zasadniczo sposobem na zdefiniowanie miejsca lub sposobu, w jaki InteractionTracker osiąga cel po przejściu w stan inercji. Można zastosować InertiaModifiers, aby wpłynąć na położenie X lub Y albo na właściwości skalowania w InteractionTracker.

Istnieją 3 typy InertiaModifiers:

  • InteractionTrackerInertiaRestingValue — sposób modyfikowania końcowej pozycji spoczynku po interakcji lub szybkości programowej. Wstępnie zdefiniowany ruch spowoduje, że InteractionTracker przejdzie do tej pozycji.
  • InteractionTrackerInertiaMotion: metoda definiowania określonego ruchu, który InteractionTracker wykona po interakcji lub prędkości ustawionej programowo. Ostateczne stanowisko będzie pochodzić z tego ruchu.
  • InteractionTrackerInertiaNaturalMotion — sposób definiowania końcowej pozycji spoczynku po interakcji lub prędkości programowej, ale z animacją opartą na fizyce (NaturalMotionAnimation).

Podczas wprowadzania inercji funkcja InteractionTracker ocenia każdy z przypisanych do niego modułów InertiaModifiers i określa, czy którykolwiek z nich ma zastosowanie. Oznacza to, że można utworzyć i przypisać wiele modułów InertiaModifiers do elementu InteractionTracker. Jednak podczas definiowania każdego z nich należy wykonać następujące czynności:

  1. Zdefiniuj warunek – wyrażenie określające instrukcję warunkową, kiedy powinien zostać zastosowany konkretny modyfikator bezwładności InertiaModifier. Często wymaga to przyjrzenia się właściwości NaturalRestingPosition w module InteractionTracker (przy ustaleniu docelowej pozycji przy domyślnej inercji).
  2. Zdefiniuj RestingValue/Motion/NaturalMotion — zdefiniuj rzeczywiste wyrażenie RestingValue, wyrażenie Motion lub NaturalMotionAnimation, które ma miejsce po spełnieniu warunku.

Uwaga / Notatka

Aspekt warunku modułu InertiaModifiers jest obliczany tylko raz, gdy element InteractionTracker wchodzi w inercję. Jednak tylko w przypadku inercjiMotion wyrażenie ruchu jest oceniane każdej ramki dla modyfikatora, którego warunek jest spełniony.

Przykład

Teraz przyjrzyjmy się, jak za pomocą InertiaModifiers można utworzyć kilka punktów zatrzymania, aby odtworzyć płynne przewijanie kanwy obrazów. W tym przykładzie każda manipulacja ma na celu potencjalnie przejście przez pojedynczy obraz — jest to często nazywane pojedynczymi obowiązkowymi punktami przyciągania.

Zacznijmy od skonfigurowania InteractionTracker, VisualInteractionSource i wyrażenia, które będzie korzystać z pozycji 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);
}

Następnie, ponieważ zachowanie pojedynczego obowiązkowego punktu przyciągania powoduje przesunięcie zawartości w górę lub w dół, potrzebujesz dwóch różnych modyfikatorów inercji: jednego, który przesuwa przewijaną zawartość w górę, i drugiego, który przesuwa ją w dół.

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

To, czy element zostanie przyciągnięty w górę czy w dół, jest określane na podstawie tego, gdzie InteractionTracker naturalnie wylądowałby względem odległości przyciągania — odległości między punktami przyciągania. Jeśli przekroczysz punkt w połowie drogi, zatrzaśnij w dół, w przeciwnym razie zatrzaśnij w górę. (W tym przykładzie przechowujesz odległość przyciągania w zestawie właściwości)

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

Ten diagram przedstawia wizualny opis logiki, która się dzieje:

Diagram modyfikatora inercji

Teraz wystarczy zdefiniować wartości spoczynkowe dla każdego InertiaModifier: przenieś pozycję InteractionTracker do poprzedniej pozycji przyciągania lub następnej.

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

Na koniec dodaj moduły InertiaModifiers do elementu InteractionTracker. Teraz, gdy InteractionTracker wejdzie w stan InertiaState, sprawdzi warunki InertiaModifiers, aby sprawdzić, czy jego pozycja powinna zostać zmodyfikowana.

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