Использование визуального слоя с 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 ниже.
Рецепты
Анимация изменения положения
Используя неявную анимацию композиции, разработчик может автоматически анимировать изменения в макете элемента относительно родительского элемента. Например, если изменить поле кнопки ниже, она автоматически будет анимироваться в его новой позиции макета.
Обзор реализации
- Получение раздаточных элементов для целевого элемента
- Создание объекта ImplicitAnimationCollection, которое автоматически анимирует изменения в свойстве Offset
- Связывание Неявного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.
Обзор реализации
- Получение раздаточных элементов для элемента узла
- Создание Windows.UI.Composition DropShadow
- Настройка DropShadow для получения фигуры из целевого элемента с помощью маски
- DropShadow является прямоугольным по умолчанию, поэтому это не обязательно, если целевой объект прямоугольный
- Присоединение тени к новому spriteVisual и установка SpriteVisual в качестве дочернего элемента узла
- Привязка размера 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.
Обзор реализации
- Получение раздаточных материалов для элемента узла
- Создание дерева эффектов размытия с помощью Win2D и CompositionEffectSourceParameter
- Создание объекта CompositionEffectBrush на основе дерева эффектов
- Задайте входные данные CompositionEffectBrush в CompositionBackdropBrush, что позволяет применять эффект к содержимому, лежащим в основе SpriteVisual.
- Задайте CompositionEffectBrush в качестве содержимого нового spriteVisual и задайте spriteVisual в качестве дочернего элемента узла. Можно использовать XamlCompositionBrushBase.
- Привязка размера 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);
}
Дополнительные ресурсы
- Обзор визуального слоя
- Класс ElementCompositionPreview
- Расширенные примеры пользовательского интерфейса и композиции в WindowsCompositionSamples GitHub
- Пример BasicXamlInterop
- Пример ParallaxingListItems