Partilhar via


Animação personalizada

A classe .NET Multi-platform App UI (.NET MAUI) Animation é o bloco de construção de todas as animações do .NET MAUI, com os ViewExtensions métodos de extensão na classe criando um ou mais Animation objetos.

Vários parâmetros devem ser especificados ao criar um objeto, incluindo valores inicial e final da propriedade que está sendo animada e um Animation retorno de chamada que altera o valor da propriedade. Um Animation objeto também pode manter uma coleção de animações filho que podem ser executadas e sincronizadas. Para obter mais informações, consulte Animações filhas.

A execução de uma animação criada com a Animation classe, que pode ou não incluir animações filhas, é obtida chamando o Commit método. Esse método especifica a duração da animação e, entre outros itens, um retorno de chamada que controla se a animação deve ser repetida.

Observação

A Animation classe tem uma IsEnabled propriedade que pode ser examinada para determinar se as animações foram desabilitadas pelo sistema operacional, como quando o modo de economia de energia é ativado.

No Android, as animações respeitam as configurações de animação do sistema:

  • Se as animações do sistema estiverem desativadas (por recursos de acessibilidade ou recursos do desenvolvedor), as novas animações saltarão imediatamente para o estado concluído.
  • Se o modo de economia de energia do dispositivo for ativado enquanto as animações estiverem em andamento, as animações saltarão imediatamente para o estado final.
  • Se as durações de animação do dispositivo estiverem definidas como zero (desabilitadas) enquanto as animações estiverem em andamento e a versão da API for 33 ou maior, as animações saltarão imediatamente para o estado concluído.

Criar uma animação

Ao criar um objeto, normalmente, um Animation mínimo de três parâmetros são necessários, conforme demonstrado no exemplo de código a seguir:

var animation = new Animation(v => image.Scale = v, 1, 2);

Neste exemplo, uma animação da Scale propriedade de uma Image instância é definida de um valor de 1 para um valor de 2. O valor animado é passado para o retorno de chamada especificado como o primeiro argumento, onde é usado para alterar o valor da Scale propriedade.

A animação é iniciada com uma chamada para o Commit método:

animation.Commit(this, "SimpleAnimation", 16, 2000, Easing.Linear, (v, c) => image.Scale = 1, () => true);

Observação

O Commit método não retorna um Task objeto. Em vez disso, as notificações são fornecidas por meio de métodos de retorno de chamada.

Os seguintes argumentos são especificados no Commit método:

  • O primeiro argumento (owner) identifica o proprietário da animação. Pode ser o elemento visual no qual a animação é aplicada ou outro elemento visual, como a página.
  • O segundo argumento (name) identifica a animação com um nome. O nome é combinado com o proprietário para identificar exclusivamente a animação. Essa identificação exclusiva pode ser usada para determinar se a animação está em execução () ou para cancelá-la (AnimationIsRunningAbortAnimation).
  • O terceiro argumento (rate) indica o número de milissegundos entre cada chamada para o método de retorno de chamada definido no Animation construtor.
  • O quarto argumento (length) indica a duração da animação, em milissegundos.
  • O quinto argumento (Easing) define a função de atenuação a ser usada na animação. Como alternativa, a função de atenuação pode ser especificada como um argumento para o Animation construtor. Para obter mais informações sobre como facilitar funções, consulte Facilitando funções.
  • O sexto argumento (finished) é um retorno de chamada que será executado quando a animação for concluída. Esse retorno de chamada usa dois argumentos, com o primeiro argumento indicando um valor final e o segundo argumento sendo definido bool como true se a animação foi cancelada. Como alternativa, o retorno de chamada pode ser especificado como um argumento para o finishedAnimation construtor. No entanto, com uma única animação, se finished os retornos de chamada forem especificados no construtor e no Commit método, somente o retorno de chamada especificado no AnimationCommit método será executado.
  • O sétimo argumento (repeat) é um retorno de chamada que permite que a animação seja repetida. Ele é chamado no final da animação e o retorno true indica que a animação deve ser repetida.

No exemplo acima, o efeito geral é criar uma animação que aumenta a propriedade de uma Image instância de 1 para 2, em 2 segundos (2000 milissegundos), usando a ScaleLinear função de atenuação. Cada vez que a animação é concluída, sua Scale propriedade é redefinida para 1 e a animação se repete.

Observação

As animações simultâneas, executadas independentemente umas das outras, podem ser construídas criando um Animation objeto para cada animação e, em seguida, chamando o Commit método em cada animação.

Animações infantis

A Animation classe também oferece suporte a animações filhas, que são objetos aos quais outros Animation objetos são Animation adicionados como filhos. Isso permite que uma série de animações seja executada e sincronizada. O exemplo de código a seguir demonstra a criação e execução de animações filho:

var parentAnimation = new Animation();
var scaleUpAnimation = new Animation(v => image.Scale = v, 1, 2, Easing.SpringIn);
var rotateAnimation = new Animation(v => image.Rotation = v, 0, 360);
var scaleDownAnimation = new Animation(v => image.Scale = v, 2, 1, Easing.SpringOut);

parentAnimation.Add(0, 0.5, scaleUpAnimation);
parentAnimation.Add(0, 1, rotateAnimation);
parentAnimation.Add(0.5, 1, scaleDownAnimation);

parentAnimation.Commit(this, "ChildAnimations", 16, 4000, null, (v, c) => SetIsEnabledButtonState(true, false));

Como alternativa, o exemplo de código pode ser escrito de forma mais concisa:

new Animation
{
    { 0, 0.5, new Animation (v => image.Scale = v, 1, 2) },
    { 0, 1, new Animation (v => image.Rotation = v, 0, 360) },
    { 0.5, 1, new Animation (v => image.Scale = v, 2, 1) }
}.Commit (this, "ChildAnimations", 16, 4000, null, (v, c) => SetIsEnabledButtonState (true, false));

Em ambos os exemplos, um objeto pai Animation é criado, ao qual objetos adicionais Animation são adicionados. Os dois primeiros argumentos para o Add método especificam quando começar e terminar a animação filho. Os valores de argumento devem estar entre 0 e 1 e representam o período relativo dentro da animação pai que a animação filho especificada estará ativa. Portanto, neste exemplo, o estará ativo para a primeira metade da animação, o estará ativo para a segunda metade da animação e o scaleUpAnimationscaleDownAnimationrotateAnimation estará ativo durante toda a duração.

O efeito geral deste exemplo é que a animação ocorre ao longo de 4 segundos (4000 milissegundos). O scaleUpAnimation anima a propriedade de 1 a Scale 2, ao longo de 2 segundos. O scaleDownAnimation então anima a Scale propriedade de 2 para 1, ao longo de 2 segundos. Enquanto ambas as animações de escala estão ocorrendo, o rotateAnimation anima a propriedade de 0 a Rotation 360, mais de 4 segundos. Ambas as animações de dimensionamento também usam funções de atenuação. A SpringIn função de atenuação faz com que a instância inicialmente diminua antes de ficar maior, e a função de atenuação faz com que a ImageSpringOut se torne menor do que seu Image tamanho real no final da animação completa.

Há várias diferenças entre um objeto que usa animações filho e um Animation que não usa:

  • Ao usar animações filhas, o retorno de chamada em uma animação filho indica quando a criança foi concluída e o retorno de chamada passado para o finishedfinishedCommit método indica quando toda a animação foi concluída.
  • Ao usar animações filhas, retornar trueCommit do repeat retorno de chamada no método não fará com que a animação se repita, mas a animação continuará a ser executada sem novos valores.
  • Ao incluir uma função de atenuação no Commit método e a função de atenuação retornar um valor maior que 1, a animação será encerrada. Se a função de atenuação retornar um valor menor que 0, o valor será fixado como 0. Para usar uma função de atenuação que retorna um valor menor que 0 ou maior que 1, ela deve ser especificada em uma das animações filhas, e não no Commit método.

A Animation classe também inclui WithConcurrent métodos que podem ser usados para adicionar animações filho a um objeto pai Animation . No entanto, seus begin valores e finish argumento não estão restritos a 0 a 1, mas apenas a parte da animação filha que corresponde a um intervalo de 0 a 1 estará ativa. Por exemplo, se uma chamada de método define uma animação filho direcionada a uma WithConcurrentScale propriedade de 1 a 6, mas com finishbegin valores e de -2 e 3, o valor de -2 corresponde a um valor de 1 e o finishbegin valor de 3 corresponde a um ScaleScale valor de 6. Como os valores fora do intervalo de 0 e 1 não desempenham nenhum papel em uma animação, a propriedade só será animada de 3 a Scale 6.

Cancelar uma animação

Um aplicativo pode cancelar uma animação personalizada com uma chamada para o método de AbortAnimation extensão:

this.AbortAnimation ("SimpleAnimation");

Como as animações são identificadas exclusivamente por uma combinação do proprietário da animação e do nome da animação, o proprietário e o nome especificados ao executar a animação devem ser especificados para cancelá-la. Portanto, este exemplo cancelará imediatamente a animação nomeada SimpleAnimation que pertence à página.

Criar uma animação personalizada

Os exemplos mostrados aqui até agora demonstraram animações que poderiam ser igualmente alcançadas com os métodos na ViewExtensions classe. No entanto, a Animation vantagem da classe é que ela tem acesso ao método de retorno de chamada, que é executado quando o valor animado é alterado. Isso permite que o retorno de chamada implemente qualquer animação desejada. Por exemplo, o exemplo de código a seguir anima a propriedade de uma página definindo-a Color.FromHsla como Color valores criados pelo método, com valores de matiz que variam de 0 a BackgroundColor 1:

new Animation (callback: v => BackgroundColor = Color.FromHsla (v, 1, 0.5),
  start: 0,
  end: 1).Commit (this, "Animation", 16, 4000, Easing.Linear, (v, c) => BackgroundColor = Colors.Black);

A animação resultante fornece a aparência de avançar o plano de fundo da página através das cores do arco-íris.

Criar um método de extensão de animação personalizado

Os métodos de extensão na ViewExtensions classe animam uma propriedade de seu valor atual para um valor especificado. Isso dificulta a criação, por exemplo, de um método de animação que possa ser usado para animar uma cor de um ColorTo valor para outro. Isso ocorre porque controles diferentes têm propriedades diferentes do tipo Color. Embora a classe defina uma BackgroundColor propriedade, essa nem sempre é a VisualElement propriedade desejada Color para animar.

A solução para esse problema é não ter o ColorTo método de destino de uma propriedade específica Color . Em vez disso, ele pode ser gravado com um método de retorno de chamada que passa o valor interpolado Color de volta para o chamador. Além disso, o método terá argumentos de início e fim Color .

O ColorTo método pode ser implementado como um método de extensão que usa o Animate método na AnimationExtensions classe para fornecer sua funcionalidade. Isso ocorre porque o Animate método pode ser usado para direcionar propriedades que não são do tipo double, conforme demonstrado no exemplo de código a seguir:

public static class ViewExtensions
{
    public static Task<bool> ColorTo(this VisualElement self, Color fromColor, Color toColor, Action<Color> callback, uint length = 250, Easing easing = null)
    {
        Func<double, Color> transform = (t) =>
            Color.FromRgba(fromColor.Red + t * (toColor.Red - fromColor.Red),
                           fromColor.Green + t * (toColor.Green - fromColor.Green),
                           fromColor.Blue + t * (toColor.Blue - fromColor.Blue),
                           fromColor.Alpha + t * (toColor.Alpha - fromColor.Alpha));
        return ColorAnimation(self, "ColorTo", transform, callback, length, easing);
    }

    public static void CancelAnimation(this VisualElement self)
    {
        self.AbortAnimation("ColorTo");
    }

    static Task<bool> ColorAnimation(VisualElement element, string name, Func<double, Color> transform, Action<Color> callback, uint length, Easing easing)
    {
        easing = easing ?? Easing.Linear;
        var taskCompletionSource = new TaskCompletionSource<bool>();

        element.Animate<Color>(name, transform, callback, 16, length, easing, (v, c) => taskCompletionSource.SetResult(c));
        return taskCompletionSource.Task;
    }
}

O Animate método requer um argumento, que é um transform método de retorno de chamada. A entrada para esse retorno de chamada é sempre um double intervalo de 0 a 1. Portanto, neste exemplo, o ColorTo método define sua própria transformação Func que aceita um intervalo de 0 a 1 e que retorna um doubleColor valor correspondente a esse valor. O Color valor é calculado interpolando os Redvalores , , BlueGreene Alpha dos dois argumentos fornecidosColor. O Color valor é então passado para o método de retorno de chamada a ser aplicado a uma propriedade. Essa abordagem permite que o ColorTo método anime qualquer propriedade especificada Color :

await Task.WhenAll(
  label.ColorTo(Colors.Red, Colors.Blue, c => label.TextColor = c, 5000),
  label.ColorTo(Colors.Blue, Colors.Red, c => label.BackgroundColor = c, 5000));
await this.ColorTo(Color.FromRgb(0, 0, 0), Color.FromRgb(255, 255, 255), c => BackgroundColor = c, 5000);
await boxView.ColorTo(Colors.Blue, Colors.Red, c => boxView.Color = c, 4000);

Neste exemplo de código, o ColorTo método anima as TextColor propriedades e de um , a propriedade de uma página e BackgroundColor a BackgroundColorColor propriedade de um LabelBoxViewarquivo .