Sdílet prostřednictvím


Aktualizace pull-to-refresh pomocí modifikátorů zdroje

V tomto článku se podrobněji podíváme na to, jak používat funkci SourceModifier systému InteractionTracker a předvedeme její použití vytvořením vlastního ovládacího prvku pro obnovu obsahu tažením.

Předpoklady

Tady předpokládáme, že znáte koncepty, které jsou popsány v těchto článcích:

Co je sourceModifier a proč jsou užitečné?

Podobně jako InertiaModifiers poskytují SourceModifiers jemnější kontrolu nad pohybem InteractionTrackeru. Na rozdíl od InertiaModifiers, které definují pohyb poté, co InteractionTracker vstoupí do setrvačnosti, SourceModifiers definují pohyb, zatímco InteractionTracker je stále ve svém interakčním stavu. V těchto případech chcete jiný zážitek než tradiční "držet za prst".

Klasickým příkladem této funkce je zážitek z přetažení a obnovení – když uživatel přetáhne seznam, aby aktualizoval obsah, seznam se pohybuje stejnou rychlostí jako prst a zastaví se po určité vzdálenosti, pohyb působí náhle a mechanicky. Přirozenější zkušeností by bylo navodit pocit odporu, zatímco uživatel aktivně interaguje se seznamem. Tato malá nuance pomáhá zajistit, aby celkový zážitek koncového uživatele při interakci se seznamem byl dynamičtější a působivější. V části Příklad si projdeme podrobnější informace o tom, jak to vytvořit.

Existují 2 typy modifikátorů zdroje:

  • DeltaPosition – je delta mezi aktuální pozicí rámce a předchozí pozicí rámce prstu během dotykové posunové interakce. Tento modifikátor zdroje vám umožňuje upravit delta pozici interakce před odesláním pro další zpracování. Jedná se o parametr typu Vector3 a vývojář může před předáním do InteractionTrackeru upravit některý z atributů X nebo Y nebo Z pozice.
  • DeltaScale – je rozdíl mezi aktuálním měřítkem snímku a předchozím měřítkem snímku, který byl použit během interakce dotykového přiblížení. Tento modifikátor zdroje umožňuje upravit úroveň přiblížení interakce. Jedná se o atribut typu float, který může vývojář před předáním do InteractionTrackeru upravit.

Když je InteractionTracker ve svém stavu Interakce, vyhodnotí každý z modifikátorů zdroje přiřazený k němu a určí, jestli se některý z nich použije. To znamená, že můžete vytvořit a přiřadit více modifikátorů zdroje k InteractionTrackeru. Při definování každého z nich ale musíte udělat toto:

  1. Definujte podmínku – výraz, který definuje podmíněný příkaz při použití tohoto konkrétního modifikátoru zdroje.
  2. Definujte DeltaPosition/DeltaScale – výraz modifikátoru zdroje, který změní DeltaPosition nebo DeltaScale, pokud je splněna výše definovaná podmínka.

Příklad

Nyní se podíváme, jak můžete pomocí Modifikátorů zdrojů vytvořit vlastní zkušenost s pull-to-refresh pomocí existujícího ovládacího prvku WinUI XAML ListView. K sestavení tohoto prostředí použijeme Canvas jako "obnovovací panel", který bude umístěn nad objektem XAML ListView.

Pro uživatelský zážitek chceme vytvořit efekt "odolnosti", protože uživatel aktivně švihem posouvá seznam (dotykem) a posun se zastaví, když pozice překročí určitý bod.

Seznam s aktualizací pull-to-refresh

Pracovní kód pro toto prostředí najdete v úložišti Windows UI Dev Labs na GitHubu. Tady je podrobný postup vytváření tohoto prostředí. V kódu XAML máte následující:

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

Vzhledem k tomu, že ListView (ThumbnailList) je ovládací prvek XAML, který se již posouvá, je nutné, aby se posouvání přeneslo na nadřazený prvek (ContentPanel), když dosáhne nejvyšší položky a nemůže se dále posouvat. (ContentPanel je místo, kde použijete modifikátory zdroje.) Aby k tomu došlo, musíte nastavit ScrollViewer.IsVerticalScrollChainingEnabled na true v ListView revize. Budete také muset nastavit režim řetězení na VisualInteractionSource na Always.

Potřebujete nastavit obslužnou rutinu PointerPressedEvent s parametrem handledEventsToo jako true. Bez této možnosti nebude UkazatelPressedEvent zřetězený s ContentPanel, protože ListView ovládací prvek označí tyto události jako zpracovávané a nebudou odeslány do vizuálního řetězu.

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

Teď jste připraveni ho svázat s InteractionTrackerem. Začněte nastavením InteractionTrackeru, VisualInteractionSource a Expression, který bude využívat pozici InteractionTrackeru.

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

Při tomto nastavení je panel aktualizace mimo oblast zobrazení ve své počáteční pozici a jediná věc, kterou uživatel vidí, je listView. Když posouvání dosáhne ContentPanel, bude aktivována událost PointerPressed, kde požádáte systém, aby používal InteractionTracker k řízení zkušenosti s manipulací.

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

Poznámka:

Pokud řetězení zpracovávaných událostí není potřeba, přidání obslužné rutiny PointerPressedEvent lze provést přímo prostřednictvím kódu XAML pomocí atributu (PointerPressed="Window_PointerPressed").

Dalším krokem je nastavení modifikátorů zdroje. K získání tohoto chování použijete 2 modifikátory zdroje; Odpor a zastavení.

  • Odpor – Přesuňte DeltaPosition.Y o polovinu rychlosti, dokud nedosáhne výšky 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;
  • Stop – Zastavit pohyb, jakmile je celý RefreshPanel na obrazovce.
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);

Tento diagram poskytuje vizualizaci nastavení SourceModifiers.

Schéma posouvání

Nyní s SourceModifiers si všimnete, že při posouvání ListView dolů a dosažení nejvyšší položky, se panel aktualizace stahuje poloviční rychlostí než posun, dokud nedosáhne výšky RefreshPanel, a pak se přestane pohybovat.

V úplné ukázce se animace klíčového rámce používá ke otočení ikony během interakce na plátně RefreshPanel. Jakýkoli obsah lze použít místo toho, nebo lze využít pozici InteractionTracker k nezávislému řízení této animace.