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


Использование визуального слоя с XAML

Большинство приложений, использующих возможности визуального слоя, будут использовать XAML для определения основного содержимого пользовательского интерфейса. В юбилейном обновлении Windows 10 существуют новые функции в платформе XAML и визуальном уровне, которые упрощают объединение этих двух технологий для создания потрясающих пользовательских возможностей. Функции взаимодействия XAML и визуального слоя можно использовать для создания расширенных анимаций и эффектов, недоступных только с помощью API XAML. В том числе:

  • Эффекты кисти, такие как размытие и заморозка стекла
  • Динамические эффекты освещения
  • Анимации на основе прокрутки и параллакс
  • Анимация автоматического макета
  • Пиксель идеальное падение тени

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

Класс XamlCompositionBrushBase

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

Дополнительные сведения об использовании кистей с пользовательским интерфейсом XAML см. в разделе "Кисти".

Примеры кода см. на странице со справочной документацией по XamlCompositionBrushBase.

Класс XamlLight

XamlLight предоставляет базовый класс для эффектов освещения XAML, которые динамически освещают область с помощью CompositionLight.

Дополнительные сведения об использовании освещения, включая элементы пользовательского интерфейса XAML, см. в разделе "Освещение ".

Примеры кода см. на справочной странице XamlLight.

Класс ElementCompositionPreview

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

  • GetElementVisual: получение визуального элемента "раздаточного" элемента, используемого для отрисовки этого элемента
  • SetElementChildVisual: задает визуальный элемент "handin" в качестве последнего дочернего элемента визуального дерева этого элемента. Этот визуальный элемент будет рисовать поверх остальной части элемента.
  • GetElementChildVisual: получение визуального набора с помощью SetElementChildVisual
  • GetScrollViewerManipulationPropertySet: получение объекта, который можно использовать для создания анимаций 60fps на основе смещения прокрутки в ScrollViewer

Замечания по ElementCompositionPreview.GetElementVisual

ElementCompositionPreview.GetElementVisual возвращает визуальный элемент "раздаточный" элемент, используемый для отрисовки заданного uiElement. Свойства, такие как Visual.Opacity, Visual.Offset и Visual.Size , задаются платформой XAML на основе состояния UIElement. Это позволяет использовать такие методы, как неявная анимация перемещения (см . рецепты).

Обратите внимание, что так как в результате макета платформы XAML заданы смещение и размер , разработчики должны быть осторожны при изменении или анимации этих свойств. Разработчики должны изменять или анимировать смещение, если верхний левый угол элемента имеет то же положение, что и его родительский элемент в макете. Размер обычно не следует изменять, но доступ к свойству может оказаться полезным. Например, примеры drop Shadow и Frosted Glass ниже используют размер раздаточных визуальных элементов в качестве входных данных для анимации.

В качестве дополнительной оговорки обновленные свойства визуального элемента раздаточного элемента не будут отражены в соответствующем UIElement. Например, если для параметра UIElement.Opacity задано значение 0.5, для соответствующего раздаточного элемента Visual Opacity задано значение 0,5. Однако при задании непрозрачности визуального элемента Visual 0,5 содержимое будет отображаться в 50 % непрозрачности, но не изменит значение соответствующего свойства Opacity UIElement.

Пример анимации смещения

Неправильное

<Border>
      <Image x:Name="MyImage" Margin="5" />
</Border>
// Doesn’t work because Image has a margin!
ElementCompositionPreview.GetElementVisual(MyImage).StartAnimation("Offset", parallaxAnimation);

Правильное

<Border>
    <Canvas Margin="5">
        <Image x:Name="MyImage" />
    </Canvas>
</Border>
// This works because the Canvas parent doesn’t generate a layout offset.
ElementCompositionPreview.GetElementVisual(MyImage).StartAnimation("Offset", parallaxAnimation);

Метод ElementCompositionPreview.SetElementChildVisual

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

Методы GetAlphaMask

Изображение, TextBlock и Фигура реализуют метод GetAlphaMask , возвращающий объект CompositionBrush , представляющий изображение серого уровня с фигурой элемента. Этот CompositionBrush может служить входным элементом для объекта Composition DropShadow, поэтому тень может отражать форму элемента вместо прямоугольника. Это обеспечивает идеальные, контурные тени для текста, изображений с альфа-фигурами и фигурами. Пример этого API см. в разделе Drop Shadow ниже.

Рецепты

Анимация изменения положения

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

Обзор реализации

  1. Получение раздаточных элементов для целевого элемента
  2. Создание объекта ImplicitAnimationCollection, которое автоматически анимирует изменения в свойстве Offset
  3. Связывание НеявногоAnimationCollection с резервным визуальным элементом
<Button x:Name="RepositionTarget" Content="Click Me" />
public MainPage()
{
    InitializeComponent();
    InitializeRepositionAnimation(RepositionTarget);
}

private void InitializeRepositionAnimation(UIElement repositionTarget)
{
    var targetVisual = ElementCompositionPreview.GetElementVisual(repositionTarget);
    Compositor compositor = targetVisual.Compositor;

    // Create an animation to animate targetVisual's Offset property to its final value
    var repositionAnimation = compositor.CreateVector3KeyFrameAnimation();
    repositionAnimation.Duration = TimeSpan.FromSeconds(0.66);
    repositionAnimation.Target = "Offset";
    repositionAnimation.InsertExpressionKeyFrame(1.0f, "this.FinalValue");

    // Run this animation when the Offset Property is changed
    var repositionAnimations = compositor.CreateImplicitAnimationCollection();
    repositionAnimations["Offset"] = repositionAnimation;

    targetVisual.ImplicitAnimations = repositionAnimations;
}

Тень

Примените тень идеального пикселя к UIElement, например эллипсу , содержащей рисунок. Так как для тени требуется spriteVisual, созданного приложением, необходимо создать элемент host, который будет содержать SpriteVisual с помощью ElementCompositionPreview.SetElementChildVisual.

Обзор реализации

  1. Получение раздаточных элементов для элемента узла
  2. Создание Windows.UI.Composition DropShadow
  3. Настройка DropShadow для получения фигуры из целевого элемента с помощью маски
    • DropShadow является прямоугольным по умолчанию, поэтому это не обязательно, если целевой объект прямоугольный
  4. Присоединение тени к новому spriteVisual и установка SpriteVisual в качестве дочернего элемента узла
  5. Привязка размера spriteVisual к размеру узла с помощью ExpressionAnimation
<Grid Width="200" Height="200">
    <Canvas x:Name="ShadowHost" />
    <Ellipse x:Name="CircleImage">
        <Ellipse.Fill>
            <ImageBrush ImageSource="Assets/Images/2.jpg" Stretch="UniformToFill" />
        </Ellipse.Fill>
    </Ellipse>
</Grid>
public MainPage()
{
    InitializeComponent();
    InitializeDropShadow(ShadowHost, CircleImage);
}

private void InitializeDropShadow(UIElement shadowHost, Shape shadowTarget)
{
    Visual hostVisual = ElementCompositionPreview.GetElementVisual(shadowHost);
    Compositor compositor = hostVisual.Compositor;

    // Create a drop shadow
    var dropShadow = compositor.CreateDropShadow();
    dropShadow.Color = Color.FromArgb(255, 75, 75, 80);
    dropShadow.BlurRadius = 15.0f;
    dropShadow.Offset = new Vector3(2.5f, 2.5f, 0.0f);
    // Associate the shape of the shadow with the shape of the target element
    dropShadow.Mask = shadowTarget.GetAlphaMask();

    // Create a Visual to hold the shadow
    var shadowVisual = compositor.CreateSpriteVisual();
    shadowVisual.Shadow = dropShadow;

    // Add the shadow as a child of the host in the visual tree
   ElementCompositionPreview.SetElementChildVisual(shadowHost, shadowVisual);

    // Make sure size of shadow host and shadow visual always stay in sync
    var bindSizeAnimation = compositor.CreateExpressionAnimation("hostVisual.Size");
    bindSizeAnimation.SetReferenceParameter("hostVisual", hostVisual);

    shadowVisual.StartAnimation("Size", bindSizeAnimation);
}

В следующих двух описаниях показаны эквиваленты C++/WinRT и C++/CX предыдущего кода C#, использующие ту же структуру XAML.

#include <winrt/Windows.UI.Composition.h>
#include <winrt/Windows.UI.Xaml.h>
#include <winrt/Windows.UI.Xaml.Hosting.h>
#include <winrt/Windows.UI.Xaml.Shapes.h>
...
MainPage()
{
    InitializeComponent();
    InitializeDropShadow(ShadowHost(), CircleImage());
}

int32_t MyProperty();
void MyProperty(int32_t value);

void InitializeDropShadow(Windows::UI::Xaml::UIElement const& shadowHost, Windows::UI::Xaml::Shapes::Shape const& shadowTarget)
{
    auto hostVisual{ Windows::UI::Xaml::Hosting::ElementCompositionPreview::GetElementVisual(shadowHost) };
    auto compositor{ hostVisual.Compositor() };

    // Create a drop shadow
    auto dropShadow{ compositor.CreateDropShadow() };
    dropShadow.Color(Windows::UI::ColorHelper::FromArgb(255, 75, 75, 80));
    dropShadow.BlurRadius(15.0f);
    dropShadow.Offset(Windows::Foundation::Numerics::float3{ 2.5f, 2.5f, 0.0f });
    // Associate the shape of the shadow with the shape of the target element
    dropShadow.Mask(shadowTarget.GetAlphaMask());

    // Create a Visual to hold the shadow
    auto shadowVisual = compositor.CreateSpriteVisual();
    shadowVisual.Shadow(dropShadow);

    // Add the shadow as a child of the host in the visual tree
    Windows::UI::Xaml::Hosting::ElementCompositionPreview::SetElementChildVisual(shadowHost, shadowVisual);

    // Make sure size of shadow host and shadow visual always stay in sync
    auto bindSizeAnimation{ compositor.CreateExpressionAnimation(L"hostVisual.Size") };
    bindSizeAnimation.SetReferenceParameter(L"hostVisual", hostVisual);

    shadowVisual.StartAnimation(L"Size", bindSizeAnimation);
}
#include "WindowsNumerics.h"

MainPage::MainPage()
{
    InitializeComponent();
    InitializeDropShadow(ShadowHost, CircleImage);
}

void MainPage::InitializeDropShadow(Windows::UI::Xaml::UIElement^ shadowHost, Windows::UI::Xaml::Shapes::Shape^ shadowTarget)
{
    auto hostVisual = Windows::UI::Xaml::Hosting::ElementCompositionPreview::GetElementVisual(shadowHost);
    auto compositor = hostVisual->Compositor;

    // Create a drop shadow
    auto dropShadow = compositor->CreateDropShadow();
    dropShadow->Color = Windows::UI::ColorHelper::FromArgb(255, 75, 75, 80);
    dropShadow->BlurRadius = 15.0f;
    dropShadow->Offset = Windows::Foundation::Numerics::float3(2.5f, 2.5f, 0.0f);
    // Associate the shape of the shadow with the shape of the target element
    dropShadow->Mask = shadowTarget->GetAlphaMask();

    // Create a Visual to hold the shadow
    auto shadowVisual = compositor->CreateSpriteVisual();
    shadowVisual->Shadow = dropShadow;

    // Add the shadow as a child of the host in the visual tree
    Windows::UI::Xaml::Hosting::ElementCompositionPreview::SetElementChildVisual(shadowHost, shadowVisual);

    // Make sure size of shadow host and shadow visual always stay in sync
    auto bindSizeAnimation = compositor->CreateExpressionAnimation("hostVisual.Size");
    bindSizeAnimation->SetReferenceParameter("hostVisual", hostVisual);

    shadowVisual->StartAnimation("Size", bindSizeAnimation);
}

Заморозка стекла

Создайте эффект, который размытие и оттенок фонового содержимого. Обратите внимание, что разработчикам необходимо установить пакет NuGet Win2D для использования эффектов. Инструкции по установке см. на домашней странице Win2D.

Обзор реализации

  1. Получение раздаточных материалов для элемента узла
  2. Создание дерева эффектов размытия с помощью Win2D и CompositionEffectSourceParameter
  3. Создание объекта CompositionEffectBrush на основе дерева эффектов
  4. Задайте входные данные CompositionEffectBrush в CompositionBackdropBrush, что позволяет применять эффект к содержимому, лежащим в основе SpriteVisual.
  5. Задайте CompositionEffectBrush в качестве содержимого нового spriteVisual и задайте spriteVisual в качестве дочернего элемента узла. Можно использовать XamlCompositionBrushBase.
  6. Привязка размера spriteVisual к размеру узла с помощью ExpressionAnimation
<Grid Width="300" Height="300" Grid.Column="1">
    <Image
        Source="Assets/Images/2.jpg"
        Width="200"
        Height="200" />
    <Canvas
        x:Name="GlassHost"
        Width="150"
        Height="300"
        HorizontalAlignment="Right" />
</Grid>
public MainPage()
{
    InitializeComponent();
    InitializeFrostedGlass(GlassHost);
}

private void InitializeFrostedGlass(UIElement glassHost)
{
    Visual hostVisual = ElementCompositionPreview.GetElementVisual(glassHost);
    Compositor compositor = hostVisual.Compositor;

    // Create a glass effect, requires Win2D NuGet package
    var glassEffect = new GaussianBlurEffect
    { 
        BlurAmount = 15.0f,
        BorderMode = EffectBorderMode.Hard,
        Source = new ArithmeticCompositeEffect
        {
            MultiplyAmount = 0,
            Source1Amount = 0.5f,
            Source2Amount = 0.5f,
            Source1 = new CompositionEffectSourceParameter("backdropBrush"),
            Source2 = new ColorSourceEffect
            {
                Color = Color.FromArgb(255, 245, 245, 245)
            }
        }
    };

    //  Create an instance of the effect and set its source to a CompositionBackdropBrush
    var effectFactory = compositor.CreateEffectFactory(glassEffect);
    var backdropBrush = compositor.CreateBackdropBrush();
    var effectBrush = effectFactory.CreateBrush();

    effectBrush.SetSourceParameter("backdropBrush", backdropBrush);

    // Create a Visual to contain the frosted glass effect
    var glassVisual = compositor.CreateSpriteVisual();
    glassVisual.Brush = effectBrush;

    // Add the blur as a child of the host in the visual tree
    ElementCompositionPreview.SetElementChildVisual(glassHost, glassVisual);

    // Make sure size of glass host and glass visual always stay in sync
    var bindSizeAnimation = compositor.CreateExpressionAnimation("hostVisual.Size");
    bindSizeAnimation.SetReferenceParameter("hostVisual", hostVisual);

    glassVisual.StartAnimation("Size", bindSizeAnimation);
}

Дополнительные ресурсы