Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
I den här artikeln tar vi en djupare titt på hur du använder en InteractionTracker-funktion SourceModifier och demonstrerar dess användning genom att skapa en anpassad pull-to-refresh-kontroll.
Förutsättningar
Här förutsätter vi att du är bekant med de begrepp som beskrivs i dessa artiklar:
- Indatadrivna animeringar
- Anpassade manipulationsupplevelser med InteractionTracker
- Relationsbaserade animeringar
Vad är en SourceModifier och varför är de användbara?
Precis som InertiaModifiers ger SourceModifiers dig finare kornkontroll över en InteractionTracker-rörelse. Men till skillnad från InertiaModifiers som definierar rörelsen när InteractionTracker har angett tröghet definierar SourceModifiers rörelsen medan InteractionTracker fortfarande är i sitt interagerande tillstånd. I dessa fall vill du ha en annan upplevelse än den traditionella "håll dig till fingret".
Ett klassiskt exempel på detta är pull-to-refresh-upplevelsen – när användaren hämtar listan för att uppdatera innehållet och listan panorerar i samma hastighet som fingret och stoppas efter ett visst avstånd skulle rörelsen kännas abrupt och mekanisk. En mer naturlig upplevelse skulle vara att introducera en känsla av motstånd medan användaren aktivt interagerar med listan. Den här lilla nyansen hjälper till att göra den övergripande slutanvändarupplevelsen av att interagera med en lista mer dynamisk och tilltalande. I avsnittet Exempel går vi in mer detaljerat på hur du skapar detta.
Det finns två typer av källmodifierare:
- DeltaPosition – är deltat mellan den aktuella rampositionen och fingrets tidigare ramposition under interaktionen med pekpannan. Med den här källmodifieraren kan du ändra deltapositionen för interaktionen innan du skickar den för vidare bearbetning. Det här är en vector3-typparameter och utvecklaren kan välja att ändra något av X- eller Y- eller Z-attributen för positionen innan de skickar den till InteractionTracker.
- DeltaScale – är deltat mellan den aktuella ramstorleken och den tidigare ramstorleken som tillämpades under interaktionen med pekzoom. Med den här källmodifieraren kan du ändra interaktionens zoomningsnivå. Det här är ett float-typattribut som utvecklaren kan ändra innan det skickas till InteractionTracker.
När InteractionTracker är i sitt interagerande tillstånd utvärderas var och en av de källmodifierare som tilldelats till den och avgör om någon av dem gäller. Det innebär att du kan skapa och tilldela flera källmodifierare till en InteractionTracker. Men när du definierar var och en måste du göra följande:
- Definiera villkoret – ett uttryck som definierar villkorssatsen när den här specifika källmodifieraren ska tillämpas.
- Definiera DeltaPosition/DeltaScale – källmodifieraruttrycket som ändrar DeltaPosition eller DeltaScale när det ovan definierade villkoret uppfylls.
Exempel
Nu ska vi titta på hur du kan använda källmodifierare för att skapa en anpassad pull-to-refresh-upplevelse med en befintlig WinUI XAML ListView-kontroll. Vi kommer att använda en Canvas som "Uppdateringspanel" som kommer att staplas ovanpå en XAML ListView för att bygga denna upplevelse.
För slutanvändarupplevelsen vill vi skapa effekten av "motstånd" eftersom användaren aktivt panorerar listan (med touch) och slutar panorera efter att positionen går längre än en viss punkt.
Arbetskoden för den här upplevelsen finns i Dev Labs-lagringsplatsen för Windows-användargränssnittet på GitHub. Här är den stegvisa genomgången av att skapa den upplevelsen. I din XAML-kod har du följande:
<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>
Eftersom ListView (ThumbnailList) är en XAML-kontroll som redan rullar, måste rullningen vara länkad till dess överordnade (ContentPanel) när den når det översta objektet och inte längre kan rulla. (ContentPanel är där du ska tillämpa källmodifierarna.) För att detta ska hända måste du ange ScrollViewer.IsVerticalScrollChainingEnabled till true i ListView-markering. Du måste också ange länkningsläget på VisualInteractionSource till Always.
Du måste ange PointerPressedEvent-hanteraren med parametern handledEventsToo som true. Utan det här alternativet kommer PointerPressedEvent inte att länkas till ContentPanel eftersom ListView-kontrollen markerar dessa händelser som hanterade och de skickas inte upp i den visuella kedjan.
//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);
Nu är du redo att koppla detta till InteractionTracker. Börja med att konfigurera InteractionTracker, VisualInteractionSource och uttrycket som ska utnyttja positionen för 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);
Med den här konfigurationen är uppdateringspanelen borta från visningsplatsen i sin startposition och allt användaren ser är listView När panoreringen når ContentPanel utlöses PointerPressed-händelsen, där du ber systemet att använda InteractionTracker för att driva manipulationsupplevelsen.
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));
}
}
Anmärkning
Om du inte behöver länka hanterade händelser kan du lägga till PointerPressedEvent-hanteraren direkt via XAML-markering med hjälp av attributet (PointerPressed="Window_PointerPressed").
Nästa steg är att konfigurera källmodifierarna. Du kommer att använda två källmodifierare för att få det här beteendet. Motstånd och stopp.
- Motstånd – Flytta DeltaPosition.Y med halva hastigheten tills den når höjden på 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;
- Stoppa – Sluta flytta när hela RefreshPanel är på skärmen.
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);
Det här diagrammet ger en visualisering av SourceModifiers-konfigurationen.
Nu med SourceModifiers kommer du att märka när du panorerar ListView nedåt och når det översta objektet, uppdateringspanelen dras ner i hälften av panoreringstakten tills den når RefreshPanel-höjden och slutar sedan att röra sig.
I det fullständiga exemplet används en nyckelbildruteanimation för att snurra en ikon vid interaktion på RefreshPanel-duken. Allt innehåll kan användas i dess ställe, eller för att driva animeringen separat, kan du använda InteractionTracker:s position.
Windows developer