Подключенная анимация для приложений Windows

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

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

Значок коллекции WinUI 3 Приложение WinUI 3 Gallery содержит интерактивные примеры элементов управления и функций WinUI. Получите приложение из Microsoft Store или просмотрите исходный код GitHub.

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

Подключенная анимация

Связанная анимация и система Fluent Design

Система Fluent Design помогает создавать современный, яркий пользовательский интерфейс, который включает свет, глубину, движение, материал и масштаб. Подключенная анимация — это компонент системы Fluent Design, который добавляет движение в приложение. Дополнительные сведения см. в статье "Проектирование приложений Windows".

Почему подключенная анимация?

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

Использование подключенной анимации

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

Настройка подключенной анимации

Подключенные анимации еще больше воплощают дизайн Fluent, предоставляя конфигурации анимации, адаптированные специально для навигации по страницам вперед и назад.

Укажите конфигурацию анимации, задав свойство Configuration в ConnectedAnimation. (Мы рассмотрим примеры этого в следующем разделе.)

В этой таблице описываются доступные конфигурации. Дополнительные сведения о принципах движения, применяемых в этих анимациях, см. в разделе "Направление" и "гравитация".

GravityConnectedAnimationConfiguration
Это конфигурация по умолчанию, и рекомендуется для перехода вперед.
Когда пользователь перемещается вперед в приложении (A до B), подключенный элемент визуально «отрывается от страницы». При этом элемент кажется, движется вперед в z-пространстве и немного опускается под действием гравитации. Чтобы преодолеть последствия гравитации, элемент получает скорость и ускоряется в его окончательном положении. Результатом является анимация масштабирования и погружения.
DirectConnectedAnimationConfiguration
Когда пользователь перемещается назад в приложении (B к A), анимация более прямая. Подключенный элемент линейно перемещается из B в A с помощью кубической функции сглаживания Безье. Обратная доступность визуального элемента возвращает пользователю предыдущее состояние как можно быстрее, сохраняя контекст потока навигации.
BasicConnectedAnimationConfiguration
Это анимация по умолчанию (и только), используемая в версиях до Windows 10 версии 1809 (SDK 17763).

Конфигурация ConnectedAnimationService

Класс ConnectedAnimationService имеет два свойства, которые применяются к отдельным анимациям, а не к общей службе.

Чтобы добиться различных эффектов, некоторые конфигурации игнорируют эти свойства в ConnectedAnimationService и используют собственные значения, как описано в этой таблице.

Конфигурация Соблюдается ли DefaultDuration? Уважает DefaultEasingFunction?
Гравитация Да Да*
* Базовый перевод из A в B использует эту функцию упрощения, но "гравитационный спад" имеет собственную функцию упрощения.
Напрямую Нет
Анимация длится 150 мс.
Нет
Использует функцию сглаживания замедления.
Базовый Да Да

Как реализовать связную анимацию

Настройка подключенной анимации включает два шага.

  1. Подготовьте объект анимации на исходной странице, который указывает системе, что исходный элемент будет участвовать в подключенной анимации.
  2. Запустите анимацию на целевой странице, передав ссылку на целевой элемент.

При переходе на исходную страницу вызовите ConnectedAnimationService.GetForCurrentView, чтобы получить экземпляр ConnectedAnimationService. Чтобы подготовить анимацию, вызовите PrepareToAnimate в этом экземпляре и передайте уникальный ключ и элемент пользовательского интерфейса, который вы хотите использовать в переходе. Уникальный ключ позволяет получить анимацию позже на целевой странице.

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

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

Подключенная анимация в интерфейсах списка и сетки

Часто требуется создать подключенную анимацию из списка или элемента управления сеткой. Для упрощения этого процесса можно использовать два метода в ListView и GridView, PrepareConnectedAnimation и TryStartConnectedAnimationAsync.

Например, предположим, что у вас есть listView , содержащий элемент с именем "PortraitEllipse" в шаблоне данных.

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

Чтобы подготовить подключенную анимацию с многоточием, соответствующим заданному элементу списка, вызовите метод PrepareConnectedAnimation с уникальным ключом, элементом и именем "PortraitEllipse".

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");
        }
    }
}

Координируемая анимация

Координируемая анимация

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

Если координируемая анимация использует конфигурацию гравитации, гравитация применяется как к подключенному элементу анимации, так и к согласованным элементам. Скоординированные элементы будут «схватываться» вместе с подключенным элементом, чтобы элементы оставались действительно согласованными.

Используйте двухпараметрическую перегрузку 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 });
     }
}

Recommendations

  • Используйте подключенную анимацию в переходах страниц, где элемент совместно используется между исходными и целевыми страницами.
  • Используйте GravityConnectedAnimationConfiguration для навигации вперед.
  • Используйте DirectConnectedAnimationConfiguration для обратной навигации.
  • Не ждите сетевые запросы или другие длительные асинхронные операции между подготовкой и запуском связанной анимации. Возможно, потребуется предварительно загрузить необходимые сведения для выполнения перехода или использовать изображение-заполнитель с низким разрешением, пока загружается изображение с высоким разрешением в целевом представлении.
  • Используйте SuppressNavigationTransitionInfo , чтобы предотвратить анимацию перехода в кадре , если используется ConnectedAnimationService, так как подключенные анимации не предназначены для одновременного использования с переходами навигации по умолчанию. Дополнительные сведения об использовании переходов навигации см. в разделе NavigationThemeTransition .

ConnectedAnimation

ConnectedAnimationService

NavigationThemeTransition