Поделиться через


Базовая анимация

Классы анимации мультиплатформенного пользовательского интерфейса приложений .NET (.NET MAUI) предназначены для различных свойств визуальных элементов, при этом обычная анимация постепенно изменяет свойство с одного значения на другое в течение определенного периода времени.

Базовые анимации можно создавать с помощью методов расширения, предоставляемых классом ViewExtensions, который работает с объектами VisualElement:

По умолчанию каждая анимация займет 250 миллисекундах. Однако при создании анимации можно указать длительность для каждой анимации.

Заметка

Класс ViewExtensions также предоставляет метод расширения LayoutTo. Однако этот метод предназначен для использования макетами для анимации переходов между состояниями макета, содержащими изменения размера и положения.

Методы расширения анимации в классе ViewExtensions являются асинхронными и возвращают объект Task<bool>. Возвращаемое значение false, если анимация завершается, и true, если анимация отменена. Поэтому при сочетании операций анимации с оператором await становится возможным создать последовательные анимации с последующими методами анимации, выполняемыми после завершения предыдущего метода. Дополнительные сведения см. в разделе Составные анимации.

Если есть требование разрешить анимацию завершить в фоновом режиме, оператор await может быть опущен. В этом сценарии методы расширения анимации быстро возвращаются после инициации, при этом анимация происходит в фоновом режиме. Эту операцию можно использовать при создании составных анимаций. Для получения дополнительной информации см. в разделе составные анимации.

В Android анимации учитывают параметры системной анимации:

  • Если анимации системы отключены (с помощью специальных возможностей или функций разработчика), новые анимации будут немедленно переходить к завершенном состоянию.
  • Если режим экономии питания устройства активируется во время выполнения анимации, анимации немедленно переходят к завершенном состоянию.
  • Если длительность анимации устройства равна нулю (отключена) во время выполнения анимации, а версия API — 33 или больше, анимация сразу перейдет к завершенном состоянию.

Одиночные анимации

Каждый метод расширения в классе ViewExtensions реализует одну операцию анимации, которая постепенно изменяет свойство с одного значения на другое значение за период времени.

Вращение

Поворот выполняется с помощью метода RotateTo, который постепенно изменяет свойство Rotation элемента:

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

В этом примере экземпляр Image повернут до 360 градусов в течение 2 секунд (2000 миллисекунд). Метод RotateTo получает текущее значение свойства Rotation элемента для начала анимации, а затем поворачивается от этого значения к первому аргументу (360). После завершения анимации свойство Rotation изображения сбрасывается до 0. Это гарантирует, что свойство Rotation не останется равным 360 после завершения анимации, что предотвратило бы дополнительные повороты.

Заметка

Помимо метода RotateTo, существуют также RotateXTo и RotateYTo методы, которые анимируют свойства RotationX и RotationY соответственно.

Относительный поворот

Относительный поворот выполняется с помощью метода RelRotateTo, который постепенно изменяет свойство Rotation элемента:

await image.RelRotateTo(360, 2000);

В этом примере экземпляр Image поворачивается на 360 градусов с начальной позиции в течение 2 секунд (2000 миллисекунд). Метод RelRotateTo получает текущее значение свойства Rotation элемента для начала анимации, а затем поворачивается от этого значения к значению плюс его первый аргумент (360). Это гарантирует, что каждая анимация всегда будет поворотом в 360 градусов с начальной позиции. Таким образом, если в то время как анимация уже выполняется, вызывают новую анимацию, она начинается с текущей позиции и может заканчиваться на позиции, которая не является кратной 360 градусам.

Масштабирование

Масштабирование выполняется с помощью метода ScaleTo, который постепенно изменяет свойство Scale элемента:

await image.ScaleTo(2, 2000);

В этом примере экземпляр Image масштабируется до размера в два раза больше за две секунды (2000 миллисекунд). Метод ScaleTo получает текущее значение свойства Scale элемента для начала анимации, а затем масштабируется с этого значения до первого аргумента. Это влияет на расширение размера изображения до дважды его размера.

Заметка

Помимо метода ScaleTo, существуют также ScaleXTo и ScaleYTo методы, которые анимируют свойства ScaleX и ScaleY соответственно.

Относительное масштабирование

Относительная масштабирование выполняется с помощью метода RelScaleTo, который постепенно изменяет свойство Scale элемента:

await image.RelScaleTo(2, 2000);

В этом примере экземпляр Image увеличивается в два раза за две секунды (2000 миллисекунд). Метод RelScaleTo получает текущее значение свойства Scale элемента для начала анимации, а затем масштабируется от этого значения до значения плюс его первого аргумента. Это гарантирует, что каждая анимация всегда будет масштабироваться в 2 раза относительно начальной позиции.

Масштабирование и поворот с привязками

Свойства AnchorX и AnchorY визуального элемента задают центр масштабирования или поворота для свойств Rotation и Scale. Поэтому их значения также влияют на методы RotateTo и ScaleTo.

Имея Image, размещённую в центре макета, следующий пример кода показывает, как повернуть изображение вокруг центра макета, задав его свойство AnchorY.

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

Чтобы повернуть экземпляр Image вокруг центра макета, свойства AnchorX и AnchorY должны иметь значения, которые соотносятся с шириной и высотой Image. В этом примере центр Image определяется как центр макета, поэтому значение по умолчанию AnchorX 0,5 не требует изменения. Однако свойство AnchorY переопределено так, чтобы представлять собой значение от верхней части Image до центральной точки макета. Это гарантирует, что Image совершает полный поворот на 360 градусов вокруг центра макета.

Перевод

Преобразование выполняется с помощью метода TranslateTo, который постепенно изменяет TranslationX и TranslationY свойства элемента:

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

В этом примере экземпляр Image перемещается горизонтально и вертикально в течение 1 секунды (1000 миллисекунд). Метод TranslateTo одновременно перемещает изображение на 100 независимых от устройств единиц влево и на 100 независимых от устройств единиц вверх. Это связано с тем, что первый и второй аргументы являются отрицательными числами. При использовании положительных чисел изображение смещается вправо и вниз.

Важный

Если элемент изначально расположен за пределами экрана, а затем перемещён на экран, после перемещения его расположение остаётся за пределами экрана, и пользователь не может взаимодействовать с ним. Поэтому рекомендуется, чтобы представление должно быть изложено в окончательной позиции, а затем все необходимые переводы.

Затухание

Увядание выполняется с помощью метода FadeTo, который постепенно изменяет свойство Opacity элемента:

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

В этом примере экземпляр Image исчезает в течение 4 секунд (4000 миллисекунд). Метод FadeTo получает текущее значение свойства Opacity элемента для начала анимации, а затем исчезает из этого значения до первого аргумента.

Составные анимации

Составная анимация — это последовательное сочетание анимаций и может быть создано с помощью оператора 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

В этом примере экземпляр Image переводится в течение 6 секунд (6000 миллисекунд). Перевод Image использует пять анимаций с оператором await, указывающим, что каждая анимация выполняется последовательно. Поэтому последующие методы анимации выполняются после завершения предыдущего метода.

Составные анимации

Составная анимация — это сочетание анимаций, в которых одновременно выполняются две или несколько анимаций. Составные анимации можно создать путем объединения ожидаемых и неожидаемых анимаций.

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

В этом примере экземпляр Image масштабируется и одновременно поворачивается в течение 4 секунд (4000 миллисекунд). Масштабирование Image использует две последовательные анимации, которые происходят параллельно с поворотом. Метод RotateTo выполняется без оператора await и немедленно завершает работу, после чего начинается первая анимация ScaleTo. Оператор await первого метода ScaleTo задерживает второй метод ScaleTo до завершения первого метода ScaleTo. На этом этапе анимация RotateTo наполовину завершена, а Image будет повернута на 180 градусов. В последние 2 секунды (2000 миллисекунд) завершаются как вторая анимация ScaleTo, так и анимация RotateTo.

Параллельное выполнение нескольких анимаций

Методы Task.WhenAny и Task.WhenAll можно использовать для одновременного выполнения нескольких асинхронных методов и, следовательно, создавать составные анимации. Оба метода возвращают объект Task и принимают коллекцию методов, которые возвращают объект Task. Метод Task.WhenAny завершается, когда любой из методов в коллекции завершает выполнение, как показано в следующем примере кода:

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

В этом примере метод Task.WhenAny содержит две задачи. Первая задача поворачивает экземпляр Image за 4 секунды (4000 миллисекунд), а вторая задача масштабирует изображение за 2 секунды (2000 миллисекунд). После завершения второй задачи вызов метода Task.WhenAny завершается. Тем не менее, несмотря на то, что метод RotateTo по-прежнему запущен, второй метод ScaleTo может начаться.

Метод Task.WhenAll завершается после завершения всех методов в коллекции, как показано в следующем примере кода:

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

В этом примере метод Task.WhenAll содержит три задачи, каждая из которых выполняется более 10 минут. Каждый Task делает другое число поворотов в 360 градусов – 307 поворотов для RotateTo, 251 поворотов для RotateXToи 199 поворотов для RotateYTo. Эти значения являются простыми числами, тем самым гарантируя, что повороты не синхронизированы и поэтому не приводят к повторяющимся паттернам.

Отмена анимаций

Метод расширения CancelAnimations используется для отмены любых анимаций, таких как поворот, масштабирование, преобразование и увядание, которые выполняются в определенной VisualElement.

image.CancelAnimations();

В этом примере все анимации, выполняемые в экземпляре Image, немедленно отменяются.