Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Les visuels de composition composent la structure de l’arborescence visuelle sur laquelle toutes les autres fonctionnalités de l’API Microsoft.UI.Composition utilisent et s’appuient. L’API permet aux développeurs de définir et de créer un ou plusieurs objets visuels, chacun représentant un nœud unique dans une arborescence visuelle.
Objets visuels
Il existe plusieurs types visuels qui composent la structure de l’arborescence visuelle ainsi qu’une classe de pinceau de base avec plusieurs sous-classes qui affectent le contenu d’un visuel :
- Visuel : objet de base, la majorité des propriétés sont ici et héritées par les autres objets visuels.
-
ContainerVisual : dérive de Visual et ajoute la possibilité de créer des enfants.
- SpriteVisual : dérive de ContainerVisual. A la possibilité d’associer un pinceau pour que le Visual puisse afficher des pixels, y compris des images, des effets ou une couleur uniforme.
- LayerVisual : dérive de ContainerVisual. Les enfants du visuel sont aplatir en une seule couche.
- ShapeVisual : dérive de ContainerVisual. Nœud d’arborescence visuelle qui est la racine d’une CompositionShape.
- RedirectVisual : dérive de ContainerVisual. Le visuel obtient son contenu d’un autre visuel.
- SceneVisual : dérive de ContainerVisual. Visuel conteneur pour les nœuds d’une scène 3D.
Vous pouvez appliquer du contenu et des effets à SpriteVisuals à l’aide de CompositionBrush et de ses sous-classes, notamment CompositionColorBrush, CompositionSurfaceBrush et CompositionEffectBrush. Pour en savoir plus sur les pinceaux, consultez La vue d’ensemble de CompositionBrush.
L’exemple CompositionVisual
Ici, nous allons examiner certains exemples de code WinUI 3 qui illustrent les trois types visuels répertoriés précédemment. Bien que cet exemple ne couvre pas les concepts tels que les animations ou les effets plus complexes, il contient les blocs de construction que tous ces systèmes utilisent. (L’exemple de code complet est répertorié à la fin de cet article.)
Dans l’exemple, il y a plusieurs carrés de couleur unie qui peuvent être cliqués et déplacés sur l’écran. Lorsqu’un carré est cliqué dessus, il arrive à l’avant, pivote à 45 degrés et devient opaque quand il est traîné.
Cela montre un certain nombre de concepts de base pour l’utilisation de l’API, notamment :
- Création d’un compositeur
- Création d’un SpriteVisual avec un CompositionColorBrush
- Découpage du visuel
- Rotation du visuel
- Réglage de l’opacité
- Modification de la position du visuel dans la collection.
Création d’un compositeur
La création d’un compositor et son stockage dans une variable à utiliser en tant que factory est une tâche simple. Dans une application WinUI, vous récupérez généralement le compositeur à partir d’un élément XAML déjà connecté à l’arborescence visuelle :
Compositor compositor = ElementCompositionPreview.GetElementVisual(MyHost).Compositor;
Si vous avez besoin d’un compositeur et que vous n’avez pas d’UIElement disponible, vous pouvez utiliser CompositionTarget.GetCompositorForCurrentThread() à la place.
Création d’un SpriteVisual et d’un ColorBrush
À l’aide du Compositor , il est facile de créer des objets chaque fois que vous en avez besoin, tels qu’un SpriteVisual et un CompositionColorBrush :
var visual = _compositor.CreateSpriteVisual();
visual.Brush = _compositor.CreateColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));
Bien qu’il ne s’agit que de quelques lignes de code, il illustre un concept puissant : les objets SpriteVisual sont le cœur du système d’effets. Le SpriteVisual permet une grande flexibilité et une interaction en couleur, en image et en création d’effet. SpriteVisual est un type visuel unique qui peut remplir un rectangle 2D avec un pinceau, dans ce cas, une couleur unie.
Découpage d’un visuel
Le compositeur peut également être utilisé pour créer des clips pour un visuel. Voici un exemple de l’exemple d’utilisation de InsetClip pour découper chaque côté du visuel :
var clip = _compositor.CreateInsetClip();
clip.LeftInset = 1.0f;
clip.RightInset = 1.0f;
clip.TopInset = 1.0f;
clip.BottomInset = 1.0f;
_currentVisual.Clip = clip;
Comme d’autres objets de l’API, InsetClip peut avoir des animations appliquées à ses propriétés.
Rotation d’un clip
Un visuel peut être transformé avec une rotation. Notez que RotationAngle prend en charge les radians et les degrés. Par défaut, il utilise les radians, mais il est facile de spécifier des degrés, comme le montre l'extrait de code suivant :
child.RotationAngleInDegrees = 45.0f;
La rotation n’est qu’un exemple d’ensemble de composants de transformation fournis par l’API pour faciliter ces tâches. D’autres incluent Offset, Scale, Orientation, RotationAxis et 4x4 TransformMatrix.
Réglage de l’opacité
La définition de l’opacité d’un visuel est une opération simple à l’aide d’une valeur float. Par exemple, dans l’exemple, tous les carrés commencent à l’opacité .8 :
visual.Opacity = 0.8f;
Comme la rotation, la propriété Opacity peut être animée.
Modification de la position du visuel dans la collection
L’API Composition permet de modifier la position d’un visuel dans un VisualCollection de plusieurs façons. Il peut être placé au-dessus d’un autre visuel avec InsertAbove, placé ci-dessous avec InsertBelow, déplacé vers le haut avec InsertAtTop ou le bas avec InsertAtBottom.
Dans l’exemple, un visuel qui a été cliqué est placé en haut :
parent.Children.InsertAtTop(_currentVisual);
Exemple complet
Dans l’exemple WinUI complet, tous les concepts ci-dessus sont utilisés ensemble pour construire et parcourir une arborescence simple d’objets visuels pour modifier l’opacité sans rendu DirectX personnalisé. L’exemple utilise un WinUI Grid pour l’entrée de pointeur et héberge l’arborescence de composition avec 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;
}
}
}
Si vous devez initialiser un compositeur avant d’avoir un élément hôte XAML, utilisez CompositionTarget.GetCompositorForCurrentThread() et attachez les visuels à votre interface utilisateur lorsqu’un élément hôte devient disponible.
Windows developer