Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Kompoziční vizuály tvoří strukturu vizuální stromové struktury, kterou používají a sestavují všechny ostatní funkce rozhraní Microsoft.UI.Composition API. Rozhraní API umožňuje vývojářům definovat a vytvářet jeden nebo mnoho vizuálních objektů, z nichž každý představuje jeden uzel ve vizuálním stromu.
Vizuální prvky
Je několik typů vizuálů, které tvoří stromovou strukturu vizuálu, a základní třída štětce s více podtřídami, které ovlivňují obsah vizuálu.
- Visual – základní objekt, většina vlastností jsou zde a dědí ostatní vizuální objekty.
-
ContainerVisual – odvozuje se z Visual a přidává možnost vytvářet podřízené prvky.
- SpriteVisual – odvozuje z ContainerVisual. Má možnost přidružit štětec, aby vizuál mohl vykreslit pixely včetně obrázků, efektů nebo plné barvy.
- LayerVisual – odvozuje z ContainerVisual. Podřízené prvky vizuálního prvku jsou zploštěné do jedné vrstvy.
- ShapeVisual – je odvozen z ContainerVisual. Uzel vizuálního stromu, který je kořenem CompositionShape.
- RedirectVisual – je odvozen z ContainerVisual. Vizuál získá svůj obsah z jiného vizuálu.
- SceneVisual – je odvozen z ContainerVisual. Vizuál kontejneru pro uzly 3D scény
Obsah a efekty můžete použít u SpriteVisuals pomocí CompositionBrush a jejích podtříd včetně CompositionColorBrush, CompositionSurfaceBrush a CompositionEffectBrush. Další informace o štětcích viz CompositionBrush Overview.
Ukázka CompositionVisual
Tady se podíváme na ukázkový kód WinUI 3, který ukazuje tři různé typy vizuálů uvedené dříve. I když tato ukázka nepokrývá koncepty, jako jsou animace nebo složitější efekty, obsahuje stavební bloky, které všechny tyto systémy používají. (Úplný vzorový kód je uvedený na konci tohoto článku.)
V ukázce je několik plných barevných čtverců, na které lze kliknout a přetáhnout o obrazovku. Když je na čtverec kliknuto, přijde do popředí, otočí se o 45 stupňů a při tažení se stane neprůhledným.
Ukazuje řadu základních konceptů pro práci s rozhraním API, mezi které patří:
- Vytvoření kompozitoru
- Vytvoření SpriteVisual pomocí CompositionColorBrush
- Úprava vizuálu
- Otočení vizuálního prvku
- Nastavení neprůhlednosti
- Změna pozice vizuálu v rámci kolekce
Vytvoření kompozitoru
Vytvoření kompozitoru a jeho uložení do proměnné pro použití jako výrobní třídy je jednoduchá úloha. V aplikaci WinUI obvykle načtete kompozitora z elementu XAML, který je již připojen ke vizuálnímu stromu.
Compositor compositor = ElementCompositionPreview.GetElementVisual(MyHost).Compositor;
Pokud potřebujete kompozitor a nemáte k dispozici „UIElement“, můžete použít CompositionTarget.GetCompositorForCurrentThread() místo něj.
Vytvoření SpriteVisual a ColorBrush
Pomocí compositoru je snadné vytvářet objekty vždy, když je potřebujete, například SpriteVisual a CompositionColorBrush:
var visual = _compositor.CreateSpriteVisual();
visual.Brush = _compositor.CreateColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));
I když je to jen několik řádků kódu, ukazuje výkonný koncept: SpriteVisual objekty jsou jádrem systému efektů. SpriteVisual umožňuje skvělou flexibilitu a vzájemnou interakci při tvorbě barev, obrázků a efektů. SpriteVisual je jeden typ vizuálu, který může vyplnit 2D obdélník štětcem, v tomto případě plnou barvou.
Oříznutí vizuálu
Compositor lze také použít k vytváření klipů ve vizuálu. Níže je příklad z ukázky použití insetClip k oříznutí jednotlivých stran vizuálu:
var clip = _compositor.CreateInsetClip();
clip.LeftInset = 1.0f;
clip.RightInset = 1.0f;
clip.TopInset = 1.0f;
clip.BottomInset = 1.0f;
_currentVisual.Clip = clip;
Stejně jako jiné objekty v rozhraní API mohou insetClip mít animace použité na jeho vlastnosti.
Otočení klipu
Vizuál lze transformovat otočením. Všimněte si, že RotationAngle podporuje radiány i stupně. Ve výchozím nastavení se jedná o radiány, ale je snadné určit stupně, jak je znázorněno v následujícím fragmentu kódu:
child.RotationAngleInDegrees = 45.0f;
Rotace je jen jedním z příkladů sady komponentů transformací poskytovaných rozhraním API, aby tyto úlohy byly jednodušší. Mezi další patří Posun, Měřítko, Orientace, RotationAxis a TransformMatrix 4x4.
Nastavení neprůhlednosti
Nastavení neprůhlednosti vizuálu je jednoduchá operace pomocí hodnoty float. Například ve vzorku začínají všechny čtverce na 0,8 neprůhlednosti:
visual.Opacity = 0.8f;
Podobně jako otočení může být vlastnost Neprůhlednost animovaná.
Změna polohy vizualizace v kolekci
Composition API umožňuje, aby se pozice vizuálu v VisualCollection mohla změnit různými způsoby. Lze ho umístit nad jiný vizuál s InsertAbove, umístit pod pomocí InsertBelow, přesunout do horní části s InsertAtTop, nebo dolů s InsertAtBottom.
V ukázce je vizuál , na který jste kliknuli, seřazený nahoru:
parent.Children.InsertAtTop(_currentVisual);
Úplný příklad
V úplné ukázce WinUI se všechny výše uvedené koncepty používají společně k vytvoření a procházení jednoduchého stromu vizuálních objektů ke změně neprůhlednosti bez vlastního vykreslování DirectX. Ukázka používá WinUI Grid pro vstup ukazatele a hostuje kompoziční strom s ElementCompositionPreview.
<Page
x:Class="CompositionVisualSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid
x:Name="MyHost"
Background="Transparent"
PointerPressed="OnPointerPressed"
PointerMoved="OnPointerMoved"
PointerReleased="OnPointerReleased" />
</Page>
using System;
using System.Numerics;
using Microsoft.UI.Composition;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Hosting;
using Microsoft.UI.Xaml.Input;
using Windows.Foundation;
using Windows.UI;
namespace CompositionVisualSample
{
public sealed partial class MainPage : Page
{
private readonly Random _random = new();
private Compositor _compositor;
private ContainerVisual _root;
private ContainerVisual _currentVisual;
private Vector2 _offsetBias;
private bool _dragging;
public MainPage()
{
InitializeComponent();
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
if (_root != null)
{
return;
}
_compositor = ElementCompositionPreview.GetElementVisual(MyHost).Compositor;
_root = _compositor.CreateContainerVisual();
ElementCompositionPreview.SetElementChildVisual(MyHost, _root);
for (int index = 0; index < 20; index++)
{
_root.Children.InsertAtTop(CreateChildElement());
}
}
private ContainerVisual CreateChildElement()
{
var element = _compositor.CreateContainerVisual();
element.Size = new Vector2(100.0f, 100.0f);
var maxX = (float)Math.Max(MyHost.ActualWidth - element.Size.X, 0.0);
var maxY = (float)Math.Max(MyHost.ActualHeight - element.Size.Y, 0.0);
element.Offset = new Vector3(
(float)(_random.NextDouble() * maxX),
(float)(_random.NextDouble() * maxY),
0.0f);
var outer = _compositor.CreateSpriteVisual();
outer.Size = new Vector2(100.0f, 100.0f);
outer.Brush = _compositor.CreateColorBrush(Colors.White);
element.Children.InsertAtTop(outer);
var inner = _compositor.CreateSpriteVisual();
inner.Offset = new Vector3(3.0f, 3.0f, 0.0f);
inner.Size = new Vector2(94.0f, 94.0f);
byte red = (byte)(0xFF * (0.2f + (_random.NextDouble() / 0.8f)));
byte green = (byte)(0xFF * (0.2f + (_random.NextDouble() / 0.8f)));
byte blue = (byte)(0xFF * (0.2f + (_random.NextDouble() / 0.8f)));
inner.Brush = _compositor.CreateColorBrush(Color.FromArgb(0xFF, red, green, blue));
outer.Children.InsertAtTop(inner);
element.Opacity = 0.8f;
return element;
}
private void OnPointerPressed(object sender, PointerRoutedEventArgs e)
{
Point position = e.GetCurrentPoint(MyHost).Position;
_currentVisual = null;
foreach (var child in _root.Children)
{
Vector3 offset = child.Offset;
Vector2 size = child.Size;
if ((position.X >= offset.X) &&
(position.X < offset.X + size.X) &&
(position.Y >= offset.Y) &&
(position.Y < offset.Y + size.Y))
{
_currentVisual = child as ContainerVisual;
_offsetBias = new Vector2(
(float)(offset.X - position.X),
(float)(offset.Y - position.Y));
}
}
if (_currentVisual != null)
{
ContainerVisual parent = (ContainerVisual)_currentVisual.Parent;
parent.Children.Remove(_currentVisual);
parent.Children.InsertAtTop(_currentVisual);
}
}
private void OnPointerMoved(object sender, PointerRoutedEventArgs e)
{
if (_currentVisual == null)
{
return;
}
if (!_dragging)
{
_currentVisual.Opacity = 1.0f;
foreach (var child in _currentVisual.Children)
{
child.RotationAngleInDegrees = 45.0f;
child.CenterPoint = new Vector3(_currentVisual.Size.X / 2, _currentVisual.Size.Y / 2, 0.0f);
break;
}
var clip = _compositor.CreateInsetClip();
clip.LeftInset = 1.0f;
clip.RightInset = 1.0f;
clip.TopInset = 1.0f;
clip.BottomInset = 1.0f;
_currentVisual.Clip = clip;
_dragging = true;
}
Point position = e.GetCurrentPoint(MyHost).Position;
_currentVisual.Offset = new Vector3(
(float)(position.X + _offsetBias.X),
(float)(position.Y + _offsetBias.Y),
0.0f);
}
private void OnPointerReleased(object sender, PointerRoutedEventArgs e)
{
if (_currentVisual == null)
{
return;
}
if (_dragging)
{
foreach (var child in _currentVisual.Children)
{
child.RotationAngle = 0.0f;
child.CenterPoint = new Vector3(0.0f, 0.0f, 0.0f);
break;
}
_currentVisual.Opacity = 0.8f;
_currentVisual.Clip = null;
_dragging = false;
}
_currentVisual = null;
}
}
}
Pokud potřebujete inicializovat kompozitor před tím, než budete mít prvek hostitele XAML, použijte CompositionTarget.GetCompositorForCurrentThread() a připojte grafiku k vašemu uživatelskému rozhraní, jakmile bude prvek hostitele k dispozici.
Windows developer