Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym artykule dowiesz się, jak używać funkcji SourceModifier usługi InteractionTracker i demonstrować jej użycie, tworząc niestandardową kontrolkę ściągania do odświeżenia.
Wymagania wstępne
W tym miejscu przyjęto założenie, że znasz pojęcia omówione w następujących artykułach:
- Animacje oparte na danych wejściowych
- Niestandardowe doświadczenia manipulowania za pomocą InteractionTracker
- Animacje oparte na relacjach
Co to jest SourceModifier i dlaczego jest przydatny?
Podobnie jak InertiaModifiers, SourceModifiers zapewniają precyzyjniejszą kontrolę nad ruchem elementu InteractionTracker. Ale w przeciwieństwie do InertiaModifiers, które definiują ruch po tym, jak InteractionTracker wchodzi w inercję, SourceModifiers definiują ruch, podczas gdy InteractionTracker jest nadal w stanie interakcji. W takich przypadkach chcesz uzyskać inne wrażenia niż tradycyjne "przyklejanie się do palca".
Klasycznym przykładem tego jest funkcja przeciągnięcia do odświeżenia — gdy użytkownik ciągnie listę, aby odświeżyć zawartość, a lista porusza się z taką samą prędkością jak palec i zatrzymuje się po określonej odległości, ruch wydaje się nagły i mechaniczny. Bardziej naturalne doświadczenie polegałoby na wprowadzeniu poczucia oporu, podczas gdy użytkownik aktywnie wchodzi w interakcję z listą. Ten mały niuans pomaga uczynić ogólne doświadczenie użytkownika końcowego podczas interakcji z listą bardziej dynamiczne i atrakcyjne. W sekcji "Przykład" omawiamy bardziej szczegółowo, jak zbudować to rozwiązanie.
Istnieją 2 typy modyfikatorów źródła:
- DeltaPosition — jest różnicą między bieżącą pozycją ramki a poprzednią pozycją ramki palca podczas interakcji z patelnią dotykową. Ten modyfikator źródła umożliwia modyfikowanie położenia różnicowego interakcji przed wysłaniem go do dalszego przetwarzania. Jest to parametr typu Vector3, a deweloper może zmodyfikować dowolne atrybuty X lub Y lub Z pozycji przed przekazaniem go do elementu InteractionTracker.
- DeltaScale — jest różnicą między bieżącą skalą ramek a poprzednią skalą ramek zastosowaną podczas interakcji z powiększeniem dotykowym. Ten modyfikator źródła umożliwia modyfikowanie poziomu powiększenia interakcji. Jest to atrybut typu zmiennoprzecinkowego, który deweloper może zmodyfikować przed przekazaniem go do InteractionTracker.
Gdy element InteractionTracker jest w stanie Interacting, ocenia każdy z przypisanych do niego modyfikatorów źródła i określa, czy którykolwiek z nich ma zastosowanie. Oznacza to, że można utworzyć i przypisać wiele modyfikatorów źródłowych do elementu InteractionTracker. Jednak podczas definiowania każdego z nich należy wykonać następujące czynności:
- Zdefiniuj warunek — wyrażenie, które definiuje instrukcję warunkową po zastosowaniu tego konkretnego modyfikatora źródła.
- Zdefiniuj wyrażenie deltaPosition/DeltaScale — modyfikator źródła, które zmienia wartość deltaPosition lub DeltaScale po spełnieniu powyższego zdefiniowanego warunku.
Przykład
Teraz przyjrzyjmy się, jak za pomocą modyfikatorów źródła utworzyć niestandardowe środowisko korzystające z gestu przeciągnięcia, aby odświeżyć istniejącą kontrolkę WinUI XAML ListView. Użyjemy Canvas jako "Panelu odświeżania", który zostanie umieszczony na XAML ListView w celu utworzenia tego środowiska.
W przypadku środowiska użytkownika końcowego chcemy utworzyć efekt "oporu", ponieważ użytkownik aktywnie przesuwa listę (z dotykiem) i przestaje przesuwać się po tym, jak pozycja wykracza poza określony punkt.
Kod roboczy dla tego środowiska można znaleźć w repozytorium Windows UI Dev Labs w witrynie GitHub. Oto krok po kroku przewodnik po tworzeniu tego doświadczenia. W kodzie znaczników XAML masz następujące elementy:
<StackPanel Height="500" MaxHeight="500" x:Name="ContentPanel" HorizontalAlignment="Left" VerticalAlignment="Top" >
<Canvas Width="400" Height="100" x:Name="RefreshPanel" >
<Image x:Name="FirstGear" Source="ms-appx:///Assets/Loading.png" Width="20" Height="20" Canvas.Left="200" Canvas.Top="70"/>
</Canvas>
<ListView x:Name="ThumbnailList"
MaxWidth="400"
Height="500"
ScrollViewer.VerticalScrollMode="Enabled" ScrollViewer.IsScrollInertiaEnabled="False" ScrollViewer.IsVerticalScrollChainingEnabled="True" >
<ListView.ItemTemplate>
……
</ListView.ItemTemplate>
</ListView>
</StackPanel>
Ponieważ element ListView (ThumbnailList) jest kontrolką XAML, która już obsługuje przewijanie, musisz połączyć przewijanie w górę z elementem nadrzędnym (ContentPanel), gdy osiągnie najwyższy element i nie może przewijać dalej. (ContentPanel to miejsce, w którym zostaną zastosowane modyfikatory źródła). Aby tak się stało, należy ustawić wartość ScrollViewer.IsVerticalScrollChainingEnabled na wartość true w znaczniku ListView. Należy również ustawić tryb tworzenia łańcucha w usłudze VisualInteractionSource na zawsze.
Należy ustawić procedurę obsługi PointerPressedEvent z parametrem handledEventsToo na wartość true. Bez tej opcji zdarzenie PointerPressedEvent nie będzie propagowane do ContentPanel, ponieważ kontrolka ListView oznaczy te zdarzenia jako obsłużone i nie zostaną przesłane w górę łańcucha wizualnego.
//The PointerPressed handler needs to be added using AddHandler method with the //handledEventsToo boolean set to "true"
//instead of the XAML element's "PointerPressed=Window_PointerPressed",
//because the list view needs to chain PointerPressed handled events as well.
ContentPanel.AddHandler(PointerPressedEvent, new PointerEventHandler( Window_PointerPressed), true);
Teraz możesz powiązać to z funkcją InteractionTracker. Zacznij od skonfigurowania InteractionTracker, VisualInteractionSource oraz wyrażenia, które będzie korzystać z pozycji InteractionTracker.
// InteractionTracker and VisualInteractionSource setup.
_root = ElementCompositionPreview.GetElementVisual(Root);
_compositor = _root.Compositor;
_tracker = InteractionTracker.Create(_compositor);
_interactionSource = VisualInteractionSource.Create(_root);
_interactionSource.PositionYSourceMode = InteractionSourceMode.EnabledWithInertia;
_interactionSource.PositionYChainingMode = InteractionChainingMode.Always;
_tracker.InteractionSources.Add(_interactionSource);
float refreshPanelHeight = (float)RefreshPanel.ActualHeight;
_tracker.MaxPosition = new Vector3((float)Root.ActualWidth, 0, 0);
_tracker.MinPosition = new Vector3(-(float)Root.ActualWidth, -refreshPanelHeight, 0);
// Use the Tacker's Position (negated) to apply to the Offset of the Image.
// The -{refreshPanelHeight} is to hide the refresh panel
m_positionExpression = _compositor.CreateExpressionAnimation($"-tracker.Position.Y - {refreshPanelHeight} ");
m_positionExpression.SetReferenceParameter("tracker", _tracker);
_contentPanelVisual.StartAnimation("Offset.Y", m_positionExpression);
Po skonfigurowaniu panel odświeżania jest poza obszarem wyświetlania w pozycji początkowej, a użytkownik widzi element listView. Gdy przesuwanie dociera do ContentPanel, zostanie wyzwolone zdarzenie PointerPressed, w którym poproś system o użycie InteractionTracker, aby sterować doświadczeniem manipulacji.
private void Window_PointerPressed(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Touch) {
// Tell the system to use the gestures from this pointer point (if it can).
_interactionSource.TryRedirectForManipulation(e.GetCurrentPoint(null));
}
}
Uwaga / Notatka
Jeśli nie jest konieczne łączenie obsługiwanych zdarzeń, obsługę zdarzenia PointerPressedEvent można dodać bezpośrednio w znacznikach XAML, używając atrybutu (PointerPressed="Window_PointerPressed").
Następnym krokiem jest skonfigurowanie modyfikatorów źródłowych. Aby uzyskać to zachowanie, będziesz używać 2 modyfikatorów źródłowych; Opór i zatrzymanie.
- Opór — przenieś deltaPosition.Y z połową prędkości, aż osiągnie wysokość RefreshPanel.
CompositionConditionalValue resistanceModifier = CompositionConditionalValue.Create (_compositor);
ExpressionAnimation resistanceCondition = _compositor.CreateExpressionAnimation(
$"-tracker.Position.Y < {pullToRefreshDistance}");
resistanceCondition.SetReferenceParameter("tracker", _tracker);
ExpressionAnimation resistanceAlternateValue = _compositor.CreateExpressionAnimation(
"source.DeltaPosition.Y / 3");
resistanceAlternateValue.SetReferenceParameter("source", _interactionSource);
resistanceModifier.Condition = resistanceCondition;
resistanceModifier.Value = resistanceAlternateValue;
- Zatrzymaj – zatrzymaj przesuwanie po tym, jak cały panel RefreshPanel znajduje się na ekranie.
CompositionConditionalValue stoppingModifier = CompositionConditionalValue.Create (_compositor);
ExpressionAnimation stoppingCondition = _compositor.CreateExpressionAnimation(
$"-tracker.Position.Y >= {pullToRefreshDistance}");
stoppingCondition.SetReferenceParameter("tracker", _tracker);
ExpressionAnimation stoppingAlternateValue = _compositor.CreateExpressionAnimation("0");
stoppingModifier.Condition = stoppingCondition;
stoppingModifier.Value = stoppingAlternateValue;
Now add the 2 source modifiers to the InteractionTracker.
List<CompositionConditionalValue> modifierList = new List<CompositionConditionalValue>()
{ resistanceModifier, stoppingModifier };
_interactionSource.ConfigureDeltaPositionYModifiers(modifierList);
Ten diagram przedstawia wizualizację konfiguracji sourceModifiers.
Teraz przy użyciu elementów SourceModifiers zauważysz, że podczas przesuwania widoku ListView w dół i docierania do najwyższego poziomu elementu, panel odświeżania jest ściągany w połowie tempa patelni, aż osiągnie wysokość RefreshPanel, a następnie przestanie się poruszać.
W pełnym przykładzie animacja klatki kluczowej służy do obracania ikony podczas interakcji w płótnie RefreshPanel. Dowolną zawartość można używać na jego miejsce lub wykorzystać pozycję InteractionTracker, aby oddzielnie prowadzić animację.