Windows 应用的连贯动画

连贯的动画让你可以通过为一个元素在两种不同视图之间的转换创建动画来创建动态且引人入胜的导航体验。 这有助于用户维持其上下文并提供不同视图之间的连贯性。

在连贯动画中,当 UI 内容发生变化时,元素似乎在两种不同视图之间保持“连贯性”,从其在源视图中的位置掠过屏幕,到达它在新视图中的目标位置。 这强调了不同视图之间的共同内容,并创建了转换过程中美观且动态的效果。

重要 API:ConnectedAnimation 类ConnectedAnimationService 类

示例

WinUI 2 库
WinUI 库

如果已安装 WinUI 2 库 应用,请单击此处 打开该应用,并查看连接动画的运行情况

在这段简短的视频中,应用使用连贯动画来为一个正在“继续”变成下一页标题中一部分的项目图像制作动画。 该效果有助于在转换过程维持用户上下文。

连接的动画

连贯动画和 Fluent 设计系统

Fluent Design System 可帮助你创建包含光线、深度、动画、材料和比例的现代粗体 UI。 连贯动画是 Fluent 设计系统的一个组成部分,它将动画添加到你的应用。 若要了解详细信息,请参阅 Fluent Design 概述

为何选择连贯动画?

在页面之间导航时,很重要的一点是让用户了解导航过后会出现哪些新内容,以及这些新内容与他们在导航时的意图有何关联。 连贯动画提供了一个强大的视觉隐喻,通过将用户的注意力转移到两个视图之间共享的内容,强调了二者之间的关系。 此外,连贯动画为页面导航增添了视觉效果和润色,这可以帮助让你的应用的动态设计与众不同。

何时使用连贯动画

连贯动画通常在更改页面时使用,但它们可被应用于你在更改 UI 中的内容时希望用户维持上下文的任何体验。 每当源视图和目标视图之间有共享的图像或其他 UI 元素时,你应该考虑使用连贯动画而不是导航转换中的钻取

配置连贯动画

重要

此功能要求应用的目标版本为 Windows 10 版本 1809 (SDK 17763) 或更高版本。 Configuration 属性在早期 SDK 中不可用。 可以使用自适应代码或条件 XAML,将低于 SDK 17763 的最低版本作为目标。 有关详细信息,请参阅版本自适应应用

从 Windows 10 版本 1809 开始,通过提供专为向前和向后翻页导航定制的动画配置,连贯动画进一步体现了 Fluent Design。

可以通过在 ConnectedAnimation 上设置 Configuration 属性来指定动画配置。 (我们将在下一部分中展示这些示例。)

下表介绍了可用配置。 有关这些动画中应用的运动原则的详细信息,请参阅方向性和重心

GravityConnectedAnimationConfiguration
这是默认配置,建议用于前进导航。
当用户在应用中向后导航时(A 到 B),连贯元素看起来像是“脱离页面”。 在此过程中,元素似乎在 z 空间中向前移动,并由于重力的影响而略微下降。 为了克服重力的影响,元素会获得速度并加速到其最终位置。 结果为“缩放和下降”动画。
DirectConnectedAnimationConfiguration
当用户在应用中向后导航(B 到 A)时,动画更直接。 连贯元素使用减速三次方贝塞尔缓动函数以线性方式从 B 转换为 A。 向后视觉对象提供尽可能快地将用户恢复到以前的状态,同时仍保持导航流的上下文。
BasicConnectedAnimationConfiguration
这是在 Windows 10 版本 1809 (SDK 17763) 之前的版本中使用的默认(且唯一)动画。

ConnectedAnimationService 配置

ConnectedAnimationService 类有两个属性,它们应用于单个动画而不是整个服务。

为了实现各种效果,某些配置将忽略 ConnectedAnimationService 上的这些属性,并改为使用自己的值,如下表中所述。

Configuration 是否遵循 DefaultDuration? 是否遵循 DefaultEasingFunction?
引力 是*
*从 A 到 B 的基本转换使用此缓动函数,但“重力下移”有自己的缓动函数。
直接
动画持续超过 150 毫秒。

使用减速缓动函数。
基本

如何实现连贯动画

设置连贯动画涉及两个步骤:

  1. 准备源页上的动画对象,这向系统表明源元素将参与连贯动画。
  2. 启动目标页上的动画,将引用传递到目标元素。

在源页中导航时,请调用 ConnectedAnimationService.GetForCurrentView 以获取 ConnectedAnimationService 实例。 要准备动画,请在此实例上调用 PrepareToAnimate,并传入你想要在转换中使用的唯一密钥和 UI 元素。 可以稍后在目标页上检索动画。

ConnectedAnimationService.GetForCurrentView()
    .PrepareToAnimate("forwardAnimation", SourceImage);

导航发生时,在目标页中启动动画。 要启动该动画,请调用 ConnectedAnimation.TryStart。 你可以通过使用你在创建动画时提供的唯一密钥调用 ConnectedAnimationService.GetAnimation,来检索正确的动画实例。

ConnectedAnimation animation =
    ConnectedAnimationService.GetForCurrentView().GetAnimation("forwardAnimation");
if (animation != null)
{
    animation.TryStart(DestinationImage);
}

前进导航

此示例演示如何使用 ConnectedAnimationService 为两个页面间的前进导航(Page_A 到 Page_B)创建转换。

前进导航的建议动画配置为 GravityConnectedAnimationConfiguration。 这是默认设置,所以不需要设置 Configuration 属性,除非你想指定一个不同的配置。

在源页中设置动画。

<!-- Page_A.xaml -->

<Image x:Name="SourceImage"
       HorizontalAlignment="Left" VerticalAlignment="Top"
       Width="200" Height="200"
       Stretch="Fill"
       Source="Assets/StoreLogo.png"
       PointerPressed="SourceImage_PointerPressed"/>
// Page_A.xaml.cs

private void SourceImage_PointerPressed(object sender, PointerRoutedEventArgs e)
{
    // Navigate to detail page.
    // Suppress the default animation to avoid conflict with the connected animation.
    Frame.Navigate(typeof(Page_B), null, new SuppressNavigationTransitionInfo());
}

protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
    ConnectedAnimationService.GetForCurrentView()
        .PrepareToAnimate("forwardAnimation", SourceImage);
    // You don't need to explicitly set the Configuration property because
    // the recommended Gravity configuration is default.
    // For custom animation, use:
    // animation.Configuration = new BasicConnectedAnimationConfiguration();
}

在目标页中启动动画。

<!-- Page_B.xaml -->

<Image x:Name="DestinationImage"
       Width="400" Height="400"
       Stretch="Fill"
       Source="Assets/StoreLogo.png" />
// Page_B.xaml.cs

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);

    ConnectedAnimation animation =
        ConnectedAnimationService.GetForCurrentView().GetAnimation("forwardAnimation");
    if (animation != null)
    {
        animation.TryStart(DestinationImage);
    }
}

后退导航

对于后退导航(Page_B 到 Page_A),请遵循相同的步骤,但会反转源页和目标页。

当用户导航回来时,他们希望应用尽快返回到之前的状态。 因此,建议的配置为 DirectConnectedAnimationConfiguration。 此动画更快、更直接,并使用减速缓动。

在源页中设置动画。

// Page_B.xaml.cs

protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
    if (e.NavigationMode == NavigationMode.Back)
    {
        ConnectedAnimation animation = 
            ConnectedAnimationService.GetForCurrentView().PrepareToAnimate("backAnimation", DestinationImage);

        // Use the recommended configuration for back animation.
        animation.Configuration = new DirectConnectedAnimationConfiguration();
    }
}

在目标页中启动动画。

// Page_A.xaml.cs

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);

    ConnectedAnimation animation =
        ConnectedAnimationService.GetForCurrentView().GetAnimation("backAnimation");
    if (animation != null)
    {
        animation.TryStart(SourceImage);
    }
}

在动画设置和启动之间,源元素会在应用的其他 UI 上方呈冻结状态。 这使你可以同时执行其他任何转换动画。 出于此原因,你在两个步骤之间不应等待超过 250 毫秒,因为源元素的存在可能会让人分心。 如果你准备一个动画且并未在三秒内启动它,则系统将释放该动画,且任何对 TryStart 的后续调用将失败。

列表和网格体验中的连贯动画

通常,你会想要以列表或网格控件为源或目标创建连贯动画。 你可以在 ListViewGridViewPrepareConnectedAnimationTryStartConnectedAnimationAsync 上使用这两种方法来简化此过程。

例如,如果你有一个在其数据模板中包含一个名为“PortraitEllipse”的元素的 ListView

<ListView x:Name="ContactsListView" Loaded="ContactsListView_Loaded">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="vm:ContactsItem">
            <Grid>
                …
                <Ellipse x:Name="PortraitEllipse" … />
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

要使用对应于给定列表项目的椭圆准备一个连贯动画,请使用唯一密钥、该项目和名称“PortraitEllipse”调用 PrepareConnectedAnimation 方法。

void PrepareAnimationWithItem(ContactsItem item)
{
     ContactsListView.PrepareConnectedAnimation("portrait", item, "PortraitEllipse");
}

若要以该元素为目标启动一个动画,例如从一个详细信息视图返回时,请使用 TryStartConnectedAnimationAsync。 如果你刚为 ListView 加载了数据源,TryStartConnectedAnimationAsync 将会等到相应的项目容器已被创建时才启动动画。

private async void ContactsListView_Loaded(object sender, RoutedEventArgs e)
{
    ContactsItem item = GetPersistedItem(); // Get persisted item
    if (item != null)
    {
        ContactsListView.ScrollIntoView(item);
        ConnectedAnimation animation =
            ConnectedAnimationService.GetForCurrentView().GetAnimation("portrait");
        if (animation != null)
        {
            await ContactsListView.TryStartConnectedAnimationAsync(
                animation, item, "PortraitEllipse");
        }
    }
}

协调动画

协调动画

一个协调动画是一种特殊类型的进入动画,其中一个元素将与连贯动画目标一并显示,当连贯动画元素在屏幕上移动时创建动画。 协调动画可以向一个转换添加多个视觉效果,并进一步将用户的注意力转移到源视图和目标视图之间共享的上下文。 在这些图像中,该项目的标题 UI 使用协调动画创建动画。

当协调动画使用重力配置时,重力将同时应用于连贯动画元素和协调元素。 协调元素将与连贯元素一起“俯冲”,使这些元素保持真正的协调。

使用 TryStart 的双参数过载将协调元素添加至连贯动画。 该示例演示了一个名为“DescriptionRoot”且将与名为“CoverImage”的连贯动画一同进入的网格布局的协调动画。

<!-- DestinationPage.xaml -->
<Grid>
    <Image x:Name="CoverImage" />
    <Grid x:Name="DescriptionRoot" />
</Grid>
// DestinationPage.xaml.cs
void OnNavigatedTo(NavigationEventArgs e)
{
    var animationService = ConnectedAnimationService.GetForCurrentView();
    var animation = animationService.GetAnimation("coverImage");

    if (animation != null)
    {
        // Don’t need to capture the return value as we are not scheduling any subsequent
        // animations
        animation.TryStart(CoverImage, new UIElement[] { DescriptionRoot });
     }
}

应做事项和禁止事项

  • 在源页面和目标页面之间有共享元素的页面转换中使用连贯动画。
  • 使用 GravityConnectedAnimationConfiguration 进行前进导航。
  • 使用 DirectConnectedAnimationConfiguration 进行后退导航。
  • 请勿等待准备和启动连贯动画之间的网络请求或其他长时间运行的异步操作。 你可能需要预加载必要信息以提前运行转换,或在将高分辨率图像加载到目标视图中时使用低分辨率占位符图像。
  • 如果你正在使用 ConnectedAnimationService,请使用 SuppressNavigationTransitionInfo 来阻止帧中的转换动画,因为连贯动画不应与默认的导航转换同时使用。 请参阅 NavigationThemeTransition 详细了解如何使用导航转换。

ConnectedAnimation

ConnectedAnimationService

NavigationThemeTransition