基本动画

.NET 多平台应用 UI (.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 实例在 2 秒(2000 毫秒)内旋转高达 360 度。 RotateTo 方法获取动画开头元素的当前 Rotation 属性值,然后从该值旋转到第一个参数(360)。 动画完成后,图像的 Rotation 属性将重置为 0。 这可确保动画结束后,Rotation 属性不会保持为 360,这将阻止其他旋转。

注意

除了 RotateTo 方法,还有 RotateXToRotateYTo 方法分别对 RotationXRotationY 属性进行动画处理。

相对旋转

使用 RelRotateTo 方法执行相对旋转,该方法会逐渐更改元素的 Rotation 属性:

await image.RelRotateTo(360, 2000);

在此示例中,Image 实例从其起始位置在 2 秒内旋转 360 度(2000 毫秒)。 RelRotateTo 方法获取动画开始时元素的当前 Rotation 属性值,然后从该值旋转到该值加上其第一个参数(360)之和。 这可确保每个动画始终从起始位置旋转 360 度。 因此,如果在动画正在进行时调用新动画,它将从当前位置开始,并且可能以不是 360 度增量的位置结束。

缩放

使用 ScaleTo 方法执行缩放,该方法会逐渐更改元素的 Scale 属性:

await image.ScaleTo(2, 2000);

在此示例中,一个 Image 实例的大小在2秒内(2000毫秒)增大到两倍。 ScaleTo 方法获取动画开头元素的当前 Scale 属性值,然后从该值缩放到第一个参数。 这会将图像的大小扩展到原来大小的两倍。

注意

除了 ScaleTo 方法,还有 ScaleXToScaleYTo 方法分别对 ScaleXScaleY 属性进行动画处理。

相对缩放

使用 RelScaleTo 方法执行相对缩放,该方法会逐渐更改元素 Scale 属性:

await image.RelScaleTo(2, 2000);

在此示例中,一个 Image 实例在 2 秒(2000 毫秒)内扩大到其原始大小的两倍。 RelScaleTo 方法获取动画开始时元素的当前 Scale 属性值,然后从该值缩放到该值加上其第一个参数的倍数。 这可确保每个动画始终从起始位置按比例放大为2倍。

使用锚点缩放和旋转

视觉元素的 AnchorXAnchorY 属性设置 RotationScale 属性的缩放或旋转中心。 因此,它们的值还会影响 RotateToScaleTo 方法。

鉴于已放置在布局中心的 Image,下面的代码示例演示如何通过设置其 AnchorY 属性围绕布局中心旋转图像:

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

若要围绕布局中心旋转 Image 实例,必须将 AnchorXAnchorY 属性设置为相对于 Image宽度和高度的值。 在此示例中,Image 的中心定义为布局的中心,因此默认 AnchorX 值 0.5 不需要更改。 但是,将 AnchorY 属性重新定义为从 Image 顶部到布局中心点的值。 这可确保 Image 在布局的中心点周围精确地旋转 360 度。

翻译

转换是使用 TranslateTo 方法执行的,该方法会逐渐更改元素的 TranslationXTranslationY 属性:

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 动画。 第一 ScaleTo 方法上的 await 运算符将延迟第二个 ScaleTo 方法,直到第一个 ScaleTo 方法完成。 此时,RotateTo 动画已完成一半,Image 将旋转 180 度。 在最后 2 秒(2000 毫秒)中,第二个 ScaleTo 动画和 RotateTo 动画都已完成。

并发运行多个动画

Task.WhenAnyTask.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 的旋转次数不同,RotateTo旋转307度,RotateXTo旋转251次,RotateYTo旋转199次。 这些值是质数,因此确保旋转不同步,因此不会导致重复模式。

取消动画

CancelAnimations 扩展方法用于取消在特定 VisualElement上运行的任何动画,例如旋转、缩放、翻译和淡化。

image.CancelAnimations();

在此示例中,在 Image 实例上运行的所有动画都会立即取消。