Animação básica

As classes de animação .NET MAUI (interface do usuário de aplicativo multiplataforma do .NET) destinam-se a propriedades diferentes de elementos visuais, com uma animação básica típica alterando progressivamente uma propriedade de um valor para outro durante um período de tempo.

Animações básicas podem ser criadas com métodos de extensão fornecidos pela classe ViewExtensions, que operam em objetos VisualElement:

Por padrão, cada animação levará 250 milissegundos. No entanto, uma duração para cada animação pode ser especificada ao criar a animação.

Nota

A classe ViewExtensions também fornece um método de extensão LayoutTo. No entanto, esse método destina-se a ser usado por layouts para animar transições entre estados de layout que contêm alterações de tamanho e posição.

Os métodos de extensão de animação na classe ViewExtensions são todos assíncronos e retornam um objeto Task<bool>. O valor retornado será false se a animação for concluída e true se a animação for cancelada. Portanto, quando as operações de animação são combinadas com o operador await, torna-se possível criar animações sequenciais com métodos de animação subsequentes em execução após a conclusão do método anterior. Para mais informações, consulte animações compostas .

Se houver um requisito para permitir que uma animação seja concluída em segundo plano, o operador await poderá ser omitido. Nesse cenário, os métodos de extensão de animação retornarão rapidamente depois de iniciar a animação, com a animação ocorrendo em segundo plano. Essa operação pode ser aproveitada ao criar animações compostas. Para obter mais informações, consulte animações compostas.

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

  • Se as animações do sistema estiverem desabilitadas (por recursos de acessibilidade ou recursos de desenvolvedor), 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 concluído.
  • 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.

Animações simples

Cada método de extensão na classe ViewExtensions implementa uma única operação de animação que altera progressivamente uma propriedade de um valor para outro durante um período de tempo.

Rotação

A rotação é executada com o método RotateTo, que altera progressivamente a propriedade Rotation de um elemento:

await image.RotateTo(360, 2000);
image.Rotation = 0;

Neste exemplo, uma instância de Image é girada até 360 graus em 2 segundos (2000 milissegundos). O método RotateTo obtém o valor atual da propriedade Rotation do elemento para o início da animação e então gira desse valor para seu primeiro argumento (360). Depois que a animação for concluída, a propriedade Rotation da imagem será redefinida para 0. Isso garante que a propriedade Rotation não permaneça em 360 após a conclusão da animação, o que impediria a ocorrência de rotações adicionais.

Nota

Além do método RotateTo, também há métodos RotateXTo e RotateYTo que animam as propriedades RotationX e RotationY, respectivamente.

Rotação relativa

A rotação relativa é executada com o método RelRotateTo, que altera progressivamente a propriedade Rotation de um elemento:

await image.RelRotateTo(360, 2000);

Neste exemplo, uma instância de Image é girada a 360 graus de sua posição inicial ao longo de 2 segundos (2000 milissegundos). O método RelRotateTo obtém o valor atual da propriedade Rotation do elemento para o início da animação e gira desse valor para o valor mais seu primeiro argumento (360). Isso garante que cada animação sempre será uma rotação de 360 graus da posição inicial. Portanto, se uma nova animação for invocada enquanto uma animação já estiver em andamento, ela começará da posição atual e poderá terminar em uma posição que não seja um incremento de 360 graus.

Escala

O dimensionamento é executado com o método ScaleTo, que altera progressivamente a propriedade Scale de um elemento:

await image.ScaleTo(2, 2000);

Neste exemplo, uma instância de Image é dimensionada até o dobro de seu tamanho em 2 segundos (2.000 milissegundos). O método ScaleTo obtém o valor atual da propriedade Scale do elemento para o início da animação e, em seguida, diminui desse valor até seu primeiro argumento. Isso tem o efeito de expandir o tamanho da imagem para o dobro de seu tamanho.

Nota

Além do método ScaleTo, também há métodos ScaleXTo e ScaleYTo que animam as propriedades ScaleX e ScaleY, respectivamente.

Dimensionamento relativo

O dimensionamento relativo é executado com o método RelScaleTo, que altera progressivamente a propriedade Scale de um elemento:

await image.RelScaleTo(2, 2000);

Neste exemplo, uma instância de Image é dimensionada até o dobro de seu tamanho em 2 segundos (2.000 milissegundos). O método RelScaleTo obtém o valor atual da propriedade Scale do elemento para o início da animação e, em seguida, escala desse valor até o valor somado ao seu primeiro argumento. Isso garante que cada animação sempre será uma ampliação por um fator de 2 a partir da posição inicial.

Dimensionamento e rotação com âncoras

As propriedades AnchorX e AnchorY de um elemento visual definem o centro de dimensionamento ou rotação para as propriedades Rotation e Scale. Portanto, seus valores também afetam os métodos RotateTo e ScaleTo.

Dado um Image que foi colocado no centro de um layout, o código de exemplo a seguir demonstra como rotacionar a imagem ao redor do centro do layout, definindo sua propriedade AnchorY.

double radius = Math.Min(absoluteLayout.Width, absoluteLayout.Height) / 2;
image.AnchorY = radius / image.Height;
await image.RotateTo(360, 2000);

Para girar a instância de Image ao redor do centro do layout, as propriedades AnchorX e AnchorY devem ser definidas como valores relativos à largura e à altura do Image. Neste exemplo, o centro do Image é definido como sendo o centro do layout e, portanto, o valor de AnchorX padrão de 0,5 não requer alteração. No entanto, a propriedade AnchorY é redefinida para ser um valor da parte superior do Image para o ponto central do layout. Isso garante que o Image faça uma rotação completa de 360 graus em torno do ponto central do layout.

Tradução

A tradução é executada com o método TranslateTo, que altera progressivamente as propriedades TranslationX e TranslationY de um elemento:

await image.TranslateTo(-100, -100, 1000);

Neste exemplo, a instância de Image é movida horizontal e verticalmente durante 1 segundo (1000 milissegundos). O método TranslateTo converte simultaneamente a imagem de 100 unidades independentes de dispositivo para a esquerda e 100 unidades independentes de dispositivo para cima. Isso ocorre porque o primeiro e o segundo argumentos são números negativos. Fornecer números positivos traduziria a imagem para a direita e para baixo.

Importante

Se um elemento for inicialmente colocado fora da tela e convertido na tela, após a tradução, o layout de entrada do elemento permanecerá fora da tela e o usuário não poderá interagir com ele. Portanto, é recomendável que uma exibição seja colocada em sua posição final e, em seguida, todas as traduções necessárias sejam executadas.

Desvanecimento

O desvanecimento é realizado com o método FadeTo, que altera progressivamente a propriedade Opacity de um elemento:

image.Opacity = 0;
await image.FadeTo(1, 4000);

Neste exemplo, a instância de Image desaparece em mais de 4 segundos (4.000 milissegundos). O método FadeTo obtém o valor atual da propriedade Opacity do elemento no início da animação e, em seguida, realiza um fade in desse valor até seu primeiro argumento.

Animações compostas

Uma animação composta é uma combinação sequencial de animações e pode ser criada com o operador await:

await image.TranslateTo(-100, 0, 1000);    // Move image left
await image.TranslateTo(-100, -100, 1000); // Move image diagonally up and left
await image.TranslateTo(100, 100, 2000);   // Move image diagonally down and right
await image.TranslateTo(0, 100, 1000);     // Move image left
await image.TranslateTo(0, 0, 1000);       // Move image up

Neste exemplo, a instância Image é traduzida em 6 segundos (6000 milissegundos). A tradução do Image usa cinco animações, com o operador await indicando que cada animação é executada sequencialmente. Portanto, os métodos de animação subsequentes são executados após a conclusão do método anterior.

Animações compostas

Uma animação composta é uma combinação de animações em que duas ou mais animações são executadas simultaneamente. As animações compostas podem ser criadas combinando animações aguardadas e não aguardadas:

image.RotateTo(360, 4000);
await image.ScaleTo(2, 2000);
await image.ScaleTo(1, 2000);

Neste exemplo, a instância Image é dimensionada e girada simultaneamente durante 4 segundos (4.000 milissegundos). A escalação do Image usa duas animações sequenciais que ocorrem no mesmo momento que a rotação. O método RotateTo é executado sem um operador de await e retorna imediatamente, com a primeira animação ScaleTo começando. O operador await no primeiro método ScaleTo atrasa o segundo método ScaleTo até que o primeiro método de ScaleTo seja concluído. Neste ponto, a animação RotateTo está metade concluída e a Image será girada 180 graus. Durante os 2 segundos finais (2000 milissegundos), a animação ScaleTo e a animação RotateTo são concluídas.

Executar várias animações simultaneamente

Os métodos Task.WhenAny e Task.WhenAll podem ser usados para executar vários métodos assíncronos simultaneamente e, portanto, podem criar animações compostas. Ambos os métodos retornam um objeto Task e aceitam uma coleção de métodos que cada um retorna um objeto Task. O método Task.WhenAny é concluído quando qualquer método em sua coleção conclui a execução, conforme demonstrado no exemplo de código a seguir:

await Task.WhenAny<bool>
(
  image.RotateTo(360, 4000),
  image.ScaleTo(2, 2000)
);
await image.ScaleTo(1, 2000);

Neste exemplo, o método Task.WhenAny contém duas tarefas. A primeira tarefa gira uma instância de Image em 4 segundos (4.000 milissegundos) e a segunda tarefa dimensiona a imagem em 2 segundos (2000 milissegundos). Quando a segunda tarefa for concluída, a chamada do método Task.WhenAny será concluída. No entanto, mesmo que o método RotateTo ainda esteja em execução, o segundo método ScaleTo pode começar.

O método Task.WhenAll é concluído quando todos os métodos em sua coleção foram concluídos, conforme demonstrado no exemplo de código a seguir:

// 10 minute animation
uint duration = 10 * 60 * 1000;
await Task.WhenAll
(
  image.RotateTo(307 * 360, duration),
  image.RotateXTo(251 * 360, duration),
  image.RotateYTo(199 * 360, duration)
);

Neste exemplo, o método Task.WhenAll contém três tarefas, cada uma delas executadas ao longo de 10 minutos. Cada Task faz um número diferente de rotações de 360 graus – 307 rotações para RotateTo, 251 rotações para RotateXToe 199 rotações para RotateYTo. Esses valores são números primos, garantindo, portanto, que as rotações não sejam sincronizadas e, portanto, não resultarão em padrões repetitivos.

Cancelando animações

O método de extensão CancelAnimations é usado para cancelar animações, como rotação, dimensionamento, translação e esmaecimento, que estão em execução em um VisualElementespecífico.

image.CancelAnimations();

Neste exemplo, todas as animações em execução na instância de Image são canceladas imediatamente.