Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Visual Komposisi membentuk struktur pohon visual yang digunakan dan dibangun oleh semua fitur lain dari Microsoft.UI.Composition API. API memungkinkan pengembang untuk menentukan dan membuat satu atau banyak objek visual, masing-masing mewakili satu simpul di pohon visual.
Visuals
Ada beberapa jenis visual yang membentuk struktur pohon visual, ditambah kelas dasar kuas dengan beberapa subkelas yang memengaruhi konten visual:
- Visual – objek dasar, sebagian besar properti ada di sini, dan diwariskan oleh objek Visual lainnya.
-
ContainerVisual – berasal dari Visual, dan menambahkan kemampuan untuk membuat anak- anak.
- SpriteVisual – berasal dari ContainerVisual. Memiliki kemampuan untuk mengaitkan kuas sehingga Visual dapat merender piksel termasuk gambar, efek, atau warna solid.
- LayerVisual – berasal dari ContainerVisual. Anak-anak visual diratakan menjadi satu lapisan.
- ShapeVisual – berasal dari ContainerVisual. Simpul pohon visual yang merupakan akar dari CompositionShape.
- RedirectVisual – berasal dari ContainerVisual. Konten visual berasal dari visual lain.
- SceneVisual – berasal dari ContainerVisual. Visual kontainer untuk simpul adegan 3D.
Anda dapat menerapkan konten dan efek ke SpriteVisuals menggunakan KomposisiBrush dan subkelasnya termasuk KomposisiColorBrush, KomposisiSurfaceBrush dan KomposisiEffectBrush. Untuk mempelajari lebih lanjut tentang kuas, lihat CompositionBrush Overview.
Sampel Komposisi Visual
Di sini, kita akan melihat beberapa kode sampel WinUI 3 yang menunjukkan tiga jenis visual berbeda yang tercantum sebelumnya. Meskipun sampel ini tidak mencakup konsep seperti animasi atau efek yang lebih kompleks, sampel ini berisi blok penyusun yang digunakan semua sistem tersebut. (Kode sampel lengkap tercantum di akhir artikel ini.)
Dalam contoh terdapat beberapa kotak berwarna solid yang dapat diklik dan diseret di sekitar layar. Ketika persegi diklik, itu akan muncul ke depan, berputar 45 derajat, dan menjadi tidak transparan ketika diseret ke sekeliling.
Ini menunjukkan sejumlah konsep dasar untuk bekerja dengan API termasuk:
- Membuat komposit
- Membuat SpriteVisual dengan CompositionColorBrush
- Pemangkasan Gambar
- Pengaturan Ulang Visual
- Mengatur Keburaman
- Mengubah letak elemen visual dalam koleksi.
Membuat Kompositor
Membuat Compositor dan menyimpannya dalam variabel untuk digunakan sebagai pembuat adalah tugas sederhana. Dalam aplikasi WinUI, Anda biasanya mengambil komposit dari elemen XAML yang sudah terhubung ke pohon visual:
Compositor compositor = ElementCompositionPreview.GetElementVisual(MyHost).Compositor;
Jika Anda memerlukan komposit dan tidak memiliki UIElement yang tersedia, Anda dapat menggunakannya CompositionTarget.GetCompositorForCurrentThread() sebagai gantinya.
Membuat SpriteVisual dan ColorBrush
Menggunakan Compositor mudah untuk membuat objek kapan pun Anda membutuhkannya, seperti SpriteVisual dan CompositionColorBrush:
var visual = _compositor.CreateSpriteVisual();
visual.Brush = _compositor.CreateColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));
Meskipun ini hanya beberapa baris kode, ini menunjukkan konsep yang kuat: Objek SpriteVisual adalah inti dari sistem efek. SpriteVisual memungkinkan fleksibilitas dan interplay yang hebat dalam pembuatan warna, gambar, dan efek. SpriteVisual adalah jenis visual tunggal yang dapat mengisi persegi panjang 2D dengan kuas, dalam hal ini, warna solid.
Pemotongan Visual
Compositor juga dapat digunakan untuk membuat klip ke Visual. Di bawah ini adalah contoh dari sampel penggunaan InsetClip untuk memangkas setiap sisi visual:
var clip = _compositor.CreateInsetClip();
clip.LeftInset = 1.0f;
clip.RightInset = 1.0f;
clip.TopInset = 1.0f;
clip.BottomInset = 1.0f;
_currentVisual.Clip = clip;
Seperti objek lain dalam API, InsetClip dapat memiliki animasi yang diterapkan ke propertinya.
Memutar Klip
Visual dapat diubah dengan rotasi. Perhatikan bahwa RotationAngle mendukung radian dan derajat. Secara default dalam radian, tetapi mudah untuk menentukan derajat seperti yang ditunjukkan dalam cuplikan berikut:
child.RotationAngleInDegrees = 45.0f;
Rotasi hanyalah salah satu contoh sekumpulan komponen transformasi yang disediakan oleh API untuk mempermudah tugas-tugas ini. Lainnya termasuk Offset, Scale, Orientation, RotationAxis, dan 4x4 TransformMatrix.
Mengatur Keburaman
Mengatur keburaman visual adalah operasi sederhana menggunakan nilai float. Misalnya, dalam sampel semua kuadrat dimulai pada keburaman .8:
visual.Opacity = 0.8f;
Seperti rotasi, properti Opacity dapat dianimasikan.
Mengubah posisi Visual dalam koleksi
API Komposisi memungkinkan posisi Visual dalam VisualCollection diubah dalam sejumlah cara. Ini dapat ditempatkan di atas Visual lain dengan InsertAbove, ditempatkan di bawah ini dengan InsertBelow, dipindahkan ke bagian atas dengan InsertAtTop, atau bagian bawah dengan InsertAtBottom.
Dalam sampel, Visual yang telah diklik diurutkan ke bagian atas:
parent.Children.InsertAtTop(_currentVisual);
Contoh Lengkap
Dalam sampel WinUI lengkap, semua konsep di atas digunakan bersama-sama untuk membangun dan berjalan pohon sederhana objek Visual untuk mengubah opasitas tanpa penyajian DirectX kustom. Contoh menggunakan WinUI Grid untuk input pointer dan menyajikan pohon komposisi dengan 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;
}
}
}
Jika Anda perlu menginisialisasi komposit sebelum Anda memiliki elemen host XAML, gunakan CompositionTarget.GetCompositorForCurrentThread() lalu lampirkan visual ke UI Anda saat elemen host tersedia.
Windows developer