Partilhar via


Criar pontos de encaixe com modificadores de inércia

Neste artigo, aprofundamos como usar a funcionalidade InertiaModifier de um InteractionTracker para criar experiências de movimento que se ajustam a um ponto específico numa aplicação WinUI.

Nas aplicações WinUI, InteractionTracker e os tipos de modificadores de inércia relacionados estão no Microsoft.UI.Composition.Interactions namespace.

Pré-requisitos

Aqui, assumimos que está familiarizado com os conceitos discutidos nestes artigos:

O que são snap points e por que são úteis?

Ao criar experiências de manipulação personalizadas, por vezes é útil criar pontos de posição especializados dentro da tela que permite deslocamento e zoom onde o InteractionTracker sempre descansará. Estes são frequentemente chamados de snap points.

Note, no exemplo seguinte, como o scroll pode deixar a interface numa posição desconfortável entre as diferentes imagens:

Rolagem sem pontos de encaixe

Se forem adicionados pontos de aderência, quando parares de deslocar as imagens, elas prendem-se numa posição especificada. Com os snap points, a experiência de percorrer as imagens torna-se muito mais limpa e responsiva.

Deslocação com um único ponto de encaixe

InteractionTracker e Modificadores de Inércia

Ao criar experiências de manipulação personalizadas com o InteractionTracker, pode criar experiências de movimento de snap point utilizando InertiaModifiers. Os Modificadores de Inércia são essencialmente uma forma de definir onde ou como o InteractionTracker chega ao seu destino ao entrar no estado de Inércia. Pode aplicar InertiaModifiers para impactar a posição X ou Y ou as propriedades de escala do InteractionTracker.

Existem 3 tipos de Modificadores de Inércia:

  • InteractionTrackerInertiaRestingValue – uma forma de modificar a posição final de repouso após uma interação ou velocidade programática. Um movimento pré-definido levará o InteractionTracker para essa posição.
  • InteractionTrackerInertiaMotion – uma forma de definir um movimento específico. O InteractionTracker realizará após uma interação ou velocidade programática. A posição final será derivada deste movimento.
  • InteractionTrackerInertiaNaturalMotion – uma forma de definir a posição final de repouso após uma interação ou velocidade programática, mas com uma animação baseada em física (NaturalMotionAnimation).

Ao introduzir a Inércia, o InteractionTracker avalia cada um dos Modificadores de Inércia atribuídos e determina se algum deles se aplica. Isto significa que pode criar e atribuir múltiplos Modificadores de Inércia a um InteractionTracker. Mas, ao definir cada uma, precisa de fazer o seguinte:

  1. Defina a Condição – uma Expressão que define a afirmação condicional em que este Modificador de Inércia específico deve ocorrer. Isto muitas vezes requer observar a NaturalRestingPosition do InteractionTracker (destino dado pela Inércia padrão).
  2. Defina o Valor de Repouso/Movimento/Movimento Natural – defina a expressão real do Valor de Repouso, expressão de Movimento ou Animação de Movimento Natural que é realizada quando a condição é atendida.

Observação

O aspecto condicional dos Modificadores de Inércia é apenas avaliado uma vez, quando o InteractionTracker entra em Inércia. No entanto, apenas para InertiaMotion, a Expressão do movimento é avaliada em cada frame para o modificador cuja condição é verdadeira.

Exemplo

Agora vamos ver como podes usar os InertiaModifiers para criar algumas experiências de snap point para recriar a tela de imagens que se desloca. Neste exemplo, cada manipulação destina-se potencialmente a mover-se através de uma única imagem – isto é frequentemente referido como Pontos de Ancoragem Obrigatórios Individuais.

Comecemos por configurar o InteractionTracker, o VisualInteractionSource e a Expressão, que vão aproveitar a posição do 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);
}

Depois, como um comportamento de Ponto de Ancoragem Única Obrigatória irá mover o conteúdo para cima ou para baixo, irá precisar de dois modificadores de inércia diferentes: um que move o conteúdo deslocável para cima e outro para baixo.

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

Se se deve encaixar para cima ou para baixo é determinado com base na posição natural do InteractionTracker em relação à distância de fixação – a distância entre os locais de fixação. Se passar do ponto médio, então ajuste para baixo, caso contrário ajuste para cima. (Neste exemplo, armazena a "snap distance" numa 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);

Este diagrama dá uma descrição visual da lógica que está a acontecer:

Diagrama de modificadores de inércia

Agora só precisas de definir os Valores de Repouso para cada Modificador de Inércia: ou moves a posição do InteractionTracker para a posição de snap anterior ou para a próxima.

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

Por fim, adicione os InertiaModifiers ao InteractionTracker. Agora, quando o InteractionTracker entra no seu Estado de Inércia, verifica as condições dos teus Modificadores de Inércia para ver se a sua posição deve ser modificada.

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