Aracılığıyla paylaş


Kompozisyon görselleri

Oluşturma Görselleri, Microsoft.UI.Composition API'sinin diğer tüm özelliklerinin kullandığı ve üzerinde derleme yaptığı görsel ağaç yapısını oluşturur. API, geliştiricilerin her biri görsel ağaçtaki tek bir düğümü temsil eden bir veya daha fazla görsel nesne tanımlamasına ve oluşturmasına olanak tanır.

Visuals

Görsel ağaç yapısını oluşturan birkaç görsel türü ve bir görselin içeriğini etkileyen birden çok alt sınıfa sahip bir temel fırça sınıfı vardır:

CompositionBrush ve CompositionColorBrush, CompositionSurfaceBrush ve CompositionEffectBrush gibi alt sınıflarını kullanarak SpriteVisuals'a içerik ve efektler uygulayabilirsiniz. Fırçalar hakkında daha fazla bilgi edinmek için bkz . CompositionBrush'a Genel Bakış.

CompositionVisual Örneği

Burada, daha önce listelenen üç farklı görsel türünü gösteren bazı WinUI 3 örnek koduna göz atacağız. Bu örnek, animasyonlar veya daha karmaşık efektler gibi kavramları kapsamasa da, bu sistemlerin tümünün kullandığı yapı taşları içerir. (Örnek kodun tamamı bu makalenin sonunda listelenmiştir.)

Örnekte, üzerine tıklanıp ekran hakkında sürüklenebilen bir dizi düz renk karesi vardır. Bir kareye tıklandığında öne geçer, 45 derece döner ve sürüklenirken opak hale gelir.

Bu, AŞAĞıDAKIler dahil olmak üzere API ile çalışmaya yönelik bir dizi temel kavramı gösterir:

  • Özyapıcı oluşturma
  • CompositionColorBrush ile SpriteVisual Oluşturma
  • Görseli Kırpma
  • Görseli Döndürme
  • Opaklığı Ayarlama
  • Görselin koleksiyondaki konumunu değiştirme.

Compositor Oluşturma

Bir Compositor oluşturmak ve bunu fabrika olarak kullanmak üzere bir değişkende depolamak basit bir görevdir. WinUI uygulamasında, oluşturucuyu genellikle görsel ağacına zaten bağlı olan bir XAML öğesinden alırsınız:

Compositor compositor = ElementCompositionPreview.GetElementVisual(MyHost).Compositor;

Bir compositor'a ihtiyacınız varsa ve kullanılabilir bir UIElement'iniz yoksa, bunun yerine kullanabilirsiniz CompositionTarget.GetCompositorForCurrentThread() .

SpriteVisual ve ColorBrush Oluşturma

Compositor'ı kullanarak SpriteVisual ve CompositionColorBrush gibi ihtiyaç duyduğunuzda kolayca nesne oluşturabilirsiniz:

var visual = _compositor.CreateSpriteVisual();
visual.Brush = _compositor.CreateColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF));

Bu yalnızca birkaç kod satırı olsa da güçlü bir kavram gösterir: SpriteVisual nesneleri, efekt sisteminin kalbidir. SpriteVisual, renk, görüntü ve efekt oluşturmada büyük esneklik ve etkileşim sağlar. SpriteVisual, bir 2D dikdörtgeni fırçayla, bu durumda düz bir renkle doldurabilen tek bir görsel türüdür.

Görsel Kırpma

Compositor, bir görsel için de klip oluşturmada kullanılabilir. Aşağıda, görselin her tarafını kırpmak için InsetClip kullanma örneğinden bir örnek verilmiştir:

var clip = _compositor.CreateInsetClip();
clip.LeftInset = 1.0f;
clip.RightInset = 1.0f;
clip.TopInset = 1.0f;
clip.BottomInset = 1.0f;
_currentVisual.Clip = clip;

API'deki diğer nesneler gibi InsetClip'te de özelliklerine animasyonlar uygulanabilir.

Klibi Döndürme

Bir Görsel döndürme ile dönüştürülebilir. RotationAngle'ın hem radyan hem de dereceyi desteklediğini unutmayın. Varsayılan olarak radyan olarak belirtilir, ancak aşağıdaki kod parçacığında gösterildiği gibi dereceleri belirtmek kolaydır:

child.RotationAngleInDegrees = 45.0f;

Döndürme, bu görevleri kolaylaştırmak için API tarafından sağlanan dönüştürme bileşenleri kümesinin yalnızca bir örneğidir. Diğerlerinde Offset, Scale, Orientation, RotationAxis ve 4x4 TransformMatrix bulunur.

Opaklığı Ayarlama

Görselin opaklığını ayarlamak, kayan değer kullanan basit bir işlemdir. Örneğin, örnekte tüm kareler .8 opaklıkta başlar:

visual.Opacity = 0.8f;

Döndürme gibi Opacity özelliği de animasyonlu olabilir.

Görselin koleksiyondaki konumunu değiştirme

Oluşturma API'si, bir Visual'ın VisualCollection'daki konumunun çeşitli yollarla değiştirilmesini sağlar. InsertAbove ile başka bir Görselin üzerine yerleştirilebilir, InsertBelow ile aşağıya yerleştirilebilir, InsertAtTop ile üste veya InsertAtBottom ile alta taşınabilir.

Örnekte, tıklanan bir Görsel en üste sıralanır:

parent.Children.InsertAtTop(_currentVisual);

Tam Örnek

Tam WinUI örneğinde, özel DirectX işlemesi olmadan opaklığı değiştirmek için Visual nesnelerin basit bir ağacını oluşturmak ve gezmek üzere yukarıda belirtilen kavramların tümü birlikte kullanılır. Örnek, işaretçi girişi için bir WinUI Grid kullanır ve ElementCompositionPreview ile oluşturma ağacını barındırır.

<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;
        }
    }
}

Bir XAML konak öğesine sahip olmadan önce bir kompozitör başlatmanız gerekiyorsa, CompositionTarget.GetCompositorForCurrentThread() kullanın ve bir konak öğesi kullanılabilir olduğunda görselleri kullanıcı arabiriminize ekleyin.