基本动画

.NET Multi-platform App UI (.NET MAUI) 动画类面向视觉元素的不同属性,典型的基本动画在一段时间内逐渐将属性从一个值更改为另一个值。

可以使用对 VisualElement 对象进行操作的 ViewExtensions 类提供的扩展方法创建基本动画:

默认情况下,每个动画将需要 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 方法之外,还有一些分别对 RotationXRotationY 属性进行动画处理的 RotateXToRotateYTo 方法。

相对旋转

使用 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 方法之外,还有一些分别对 ScaleXScaleY 属性进行动画处理的 ScaleXToScaleYTo 方法。

相对缩放

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

取消动画

应用可以通过调用 CancelAnimations 扩展方法取消一个或多个动画:

image.CancelAnimations();

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