WinUI 應用程式中螢幕上顯示的一切,都是因為被畫筆刷出來的。 畫筆讓你能繪製使用者介面(UI)物件,內容從純色到圖像、繪圖,甚至複雜的效果鏈皆有。 本主題介紹使用 CompositionBrush 繪畫的概念。
在使用 WinUI XAML 應用程式時,你可以選擇用 XAML 筆刷 或 CompositionBrush 來繪製 UIElement。 通常,如果你的情境已經支援某種 XAML 筆刷,那麼選擇會比較容易。 例如,讓按鈕的顏色動畫化,或用圖片改變文字填充或形狀。 如果您需要一些 XAML 筆刷不支援的功能,比如動畫遮罩、動畫九宮格拉伸或效果鏈,您可以使用 CompositionBrush 透過 XamlCompositionBrushBase 來繪製 UIElement。
在處理視覺圖層時,必須使用 CompositionBrush 來繪製 SpriteVisual 的區域。
先決條件
本概述假設您熟悉基本 Composition 應用程式的結構,如 視覺層概述所述。
用合成畫筆作畫
CompositionBrush 用其輸出來渲染一個區域。 不同的筆刷有不同類型的輸出。 有些畫筆會用純色繪製區域,有些則是漸層、圖像、自訂繪圖或特效。 也有專門的筆刷可以改變其他筆刷的行為。 例如,可以使用不透明度遮罩控制 CompositionBrush 繪製的區域,或使用九格網格來控制 CompositionBrush 在繪製區域時施加的拉伸。 CompositionBrush 可分為以下其中一種類型:
| Class | 詳細資料 |
|---|---|
| CompositionColorBrush | 用純色塗上區域 |
| CompositionSurfaceBrush | 用 ICompositionSurface 的內容物繪製一個區域 |
| 合成效果筆刷 | 用組合效果繪製區域 |
| CompositionMaskBrush | 用帶有不透明度遮罩的 CompositionBrush 繪製視覺效果 |
| 合成九宮格刷 | 使用 NineGrid 拉伸技術,使用 CompositionBrush 繪製區域 |
| Composition線性漸層筆刷 | 以線性漸層繪製區域 |
| CompositionRadialGradientBrush | 以放射狀漸層填滿區域 |
| Composition背景筆刷 | 透過取樣來自應用程式或桌面上直接位於應用程式視窗後方的背景像素來繪製區域。 可作為另一個 CompositionBrush(例如 CompositionEffectBrush)的輸入使用 |
用純色油漆
CompositionColorBrush 會用純色塗上一個區域。 有多種方式可以指定 SolidColorBrush 的顏色。 例如,你可以指定其 alpha、red、blue 和 green(ARGB)通道,或使用 Colors 類別中預設的顏色之一。
以下的插圖與程式碼展示了一個小型視覺樹狀結構,用黑色畫筆描繪並用純色畫筆繪製,該畫筆的顏色值為0x9ACD32。
Compositor _compositor;
ContainerVisual _container;
SpriteVisual _colorVisual1, _colorVisual2;
CompositionColorBrush _blackBrush, _greenBrush;
_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
_container = _compositor.CreateContainerVisual();
_blackBrush = _compositor.CreateColorBrush(Colors.Black);
_colorVisual1 = _compositor.CreateSpriteVisual();
_colorVisual1.Brush = _blackBrush;
_colorVisual1.Size = new Vector2(156, 156);
_colorVisual1.Offset = new Vector3(0, 0, 0);
_container.Children.InsertAtBottom(_colorVisual1);
_greenBrush = _compositor.CreateColorBrush(Color.FromArgb(0xff, 0x9A, 0xCD, 0x32));
_colorVisual2 = _compositor.CreateSpriteVisual();
_colorVisual2.Brush = _greenBrush;
_colorVisual2.Size = new Vector2(150, 150);
_colorVisual2.Offset = new Vector3(3, 3, 0);
_container.Children.InsertAtBottom(_colorVisual2);
線性漸層的油漆
構圖線性漸層 畫筆以線性漸層繪製區域。 線性漸層會在一條線上混合兩種或以上顏色,即漸層軸。 你可以使用 GradientStop 物件來指定漸層中的顏色及其位置。
以下的插圖與程式碼展示了一個使用 LinearGradientBrush 繪製的 SpriteVisual ,帶有兩個色位,並以紅色和黃色為主。
Compositor _compositor;
SpriteVisual _gradientVisual;
CompositionLinearGradientBrush _redyellowBrush;
_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
_redyellowBrush = _compositor.CreateLinearGradientBrush();
_redyellowBrush.ColorStops.Add(_compositor.CreateColorGradientStop(0, Colors.Red));
_redyellowBrush.ColorStops.Add(_compositor.CreateColorGradientStop(1, Colors.Yellow));
_gradientVisual = _compositor.CreateSpriteVisual();
_gradientVisual.Brush = _redyellowBrush;
_gradientVisual.Size = new Vector2(156, 156);
帶有放射狀漸層的油漆
CompositionRadialGradientBrush會以放射狀漸層繪製區域。 徑向漸層會融合兩種或以上顏色,漸層從橢圓中心開始,終點為橢圓半徑。 GradientStop 物件用來定義顏色及其在漸變中的位置。
以下的插圖與程式碼展示了一個使用 RadialGradientBrush 和 2 GradientStops 繪製的 SpriteVisual 版本。
Compositor _compositor;
SpriteVisual _gradientVisual;
CompositionRadialGradientBrush RGBrush;
_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
RGBrush = _compositor.CreateRadialGradientBrush();
RGBrush.ColorStops.Add(_compositor.CreateColorGradientStop(0, Colors.Aquamarine));
RGBrush.ColorStops.Add(_compositor.CreateColorGradientStop(1, Colors.DeepPink));
_gradientVisual = _compositor.CreateSpriteVisual();
_gradientVisual.Brush = RGBrush;
_gradientVisual.Size = new Vector2(200, 200);
用圖像作畫
CompositionSurfaceBrush 會將像素渲染到一個 ICompositionSurface 上的區域。 例如,CompositionSurfaceBrush 可以使用 LoadedImageSurface API,將影像渲染到 ICompositionSurface 上,以繪製區域。
以下的插圖與程式碼展示了一個 SpriteVisual,這個視覺元素以甘草的點陣圖進行繪製,並透過 LoadedImageSurface 將其渲染到 ICompositionSurface。 CompositionSurfaceBrush 的特性可用於在視覺範圍內拉伸和對齊點陣圖。
Compositor _compositor;
SpriteVisual _imageVisual;
CompositionSurfaceBrush _imageBrush;
_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
_imageBrush = _compositor.CreateSurfaceBrush();
// The loadedSurface has a size of 0x0 till the image has been downloaded, decoded and loaded to the surface. We can assign the surface to the CompositionSurfaceBrush and it will show up once the image is loaded to the surface.
LoadedImageSurface _loadedSurface = LoadedImageSurface.StartLoadFromUri(new Uri("ms-appx:///Assets/licorice.jpg"));
_imageBrush.Surface = _loadedSurface;
_imageVisual = _compositor.CreateSpriteVisual();
_imageVisual.Brush = _imageBrush;
_imageVisual.Size = new Vector2(156, 156);
用自訂圖畫上色
CompositionSurfaceBrush 也可用來繪製區域,使用 Win2D(或 D2D)渲染的 ICompositionSurface 的像素。
以下程式碼顯示了一個以 Win2D 繪製於 ICompositionSurface 上的文字內容填滿的 SpriteVisual。 若要在 WinUI 中使用 Win2D,請在您的專案中安裝 Microsoft.Graphics.Win2D NuGet 套件 。
Compositor _compositor;
CanvasDevice _device;
CompositionGraphicsDevice _compositionGraphicsDevice;
SpriteVisual _drawingVisual;
CompositionSurfaceBrush _drawingBrush;
_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
_device = CanvasDevice.GetSharedDevice();
_compositionGraphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(_compositor, _device);
_drawingBrush = _compositor.CreateSurfaceBrush();
CompositionDrawingSurface _drawingSurface = _compositionGraphicsDevice.CreateDrawingSurface(
new Size(256, 256),
DirectXPixelFormat.B8G8R8A8UIntNormalized,
DirectXAlphaMode.Premultiplied);
using (var ds = CanvasComposition.CreateDrawingSession(_drawingSurface))
{
ds.Clear(Colors.Transparent);
var rect = new Rect(new Point(2, 2), (_drawingSurface.Size.ToVector2() - new Vector2(4, 4)).ToSize());
ds.FillRoundedRectangle(rect, 15, 15, Colors.LightBlue);
ds.DrawRoundedRectangle(rect, 15, 15, Colors.Gray, 2);
ds.DrawText("This is a composition drawing surface", rect, Colors.Black, new CanvasTextFormat()
{
FontFamily = "Comic Sans MS",
FontSize = 32,
WordWrapping = CanvasWordWrapping.WholeWord,
VerticalAlignment = CanvasVerticalAlignment.Center,
HorizontalAlignment = CanvasHorizontalAlignment.Center
});
}
_drawingBrush.Surface = _drawingSurface;
_drawingVisual = _compositor.CreateSpriteVisual();
_drawingVisual.Brush = _drawingBrush;
_drawingVisual.Size = new Vector2(156, 156);
同樣地,CompositionSurfaceBrush 也可用來使用 Win2D 互操作來繪製帶有 SwapChain 的 SpriteVisual。 本範例 提供了如何使用 Win2D 以交換鏈(swapchain)繪製 SpriteVisual 的範例。
用影片來繪畫
CompositionSurfaceBrush 也可用來繪製一個區域,這些像素來自 ICompositionSurface 的像素,這些像素是透過 MediaPlayer 類別載入的影片所渲染的。
以下程式碼顯示一個 SpriteVisual,其中附著了一個載入至 ICompositionSurface 的影片。
Compositor _compositor;
SpriteVisual _videoVisual;
CompositionSurfaceBrush _videoBrush;
_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
// MediaPlayer setup with a source URI.
_mediaPlayer = new MediaPlayer();
// Get a source from a URI. This could also come from a file or a stream.
var source = MediaSource.CreateFromUri(new Uri("https://go.microsoft.com/fwlink/?LinkID=809007&clcid=0x409"));
var item = new MediaPlaybackItem(source);
_mediaPlayer.Source = item;
_mediaPlayer.IsLoopingEnabled = true;
// Get the surface from MediaPlayer and put it on a brush.
_videoSurface = _mediaPlayer.GetSurface(_compositor);
_videoBrush = _compositor.CreateSurfaceBrush(_videoSurface.CompositionSurface);
_videoVisual = _compositor.CreateSpriteVisual();
_videoVisual.Brush = _videoBrush;
_videoVisual.Size = new Vector2(156, 156);
帶有濾鏡效果的油漆
CompositionEffectBrush 使用 CompositionEffect 的輸出來繪製一個區域。 視覺圖層中的效果可被視為可動畫化的濾鏡效果,套用於一組來源內容,如顏色、漸層、影像、影片、交換鏈、UI 區域或視覺樹。 來源內容通常由另一個 "CompositionBrush" 指定。
以下的插圖與程式碼展示了一個塗有貓咪圖像並套用去飽和濾鏡效果的 SpriteVisual 畫面。
Compositor _compositor;
SpriteVisual _effectVisual;
CompositionEffectBrush _effectBrush;
_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
var graphicsEffect = new SaturationEffect
{
Saturation = 0.0f,
Source = new CompositionEffectSourceParameter("mySource")
};
var effectFactory = _compositor.CreateEffectFactory(graphicsEffect);
_effectBrush = effectFactory.CreateBrush();
CompositionSurfaceBrush surfaceBrush = _compositor.CreateSurfaceBrush();
LoadedImageSurface loadedSurface = LoadedImageSurface.StartLoadFromUri(new Uri("ms-appx:///Assets/cat.jpg"));
surfaceBrush.Surface = loadedSurface;
_effectBrush.SetSourceParameter("mySource", surfaceBrush);
_effectVisual = _compositor.CreateSpriteVisual();
_effectVisual.Brush = _effectBrush;
_effectVisual.Size = new Vector2(156, 156);
欲了解更多使用 CompositionBrushes 建立效果的資訊,請參見 視覺圖層的效果
使用帶有不透明遮罩的CompositionBrush進行繪製
CompositionMaskBrush 用帶有不透明度遮罩的 CompositionBrush 來繪製區域。 不透明度遮罩的來源可以是任何類型的 CompositionBrush,包括 CompositionColorBrush、CompositionLinearGradientBrush、CompositionSurfaceBrush、CompositionEffectBrush 或 CompositionNineGridBrush。 不透明度遮罩必須指定為 CompositionSurfaceBrush。
以下的插圖與程式碼展示了如何使用 CompositionMaskBrush 繪製 SpriteVisual。 遮罩的來源是一個 CompositionLinearGradientBrush,該畫筆使用一個圓形影像作為遮罩來形成圓形效果。
Compositor _compositor;
SpriteVisual _maskVisual;
CompositionMaskBrush _maskBrush;
_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
_maskBrush = _compositor.CreateMaskBrush();
CompositionLinearGradientBrush _sourceGradient = _compositor.CreateLinearGradientBrush();
_sourceGradient.ColorStops.Add(_compositor.CreateColorGradientStop(0,Colors.Red));
_sourceGradient.ColorStops.Add(_compositor.CreateColorGradientStop(1,Colors.Yellow));
_maskBrush.Source = _sourceGradient;
LoadedImageSurface loadedSurface = LoadedImageSurface.StartLoadFromUri(new Uri("ms-appx:///Assets/circle.png"), new Size(156.0, 156.0));
_maskBrush.Mask = _compositor.CreateSurfaceBrush(loadedSurface);
_maskVisual = _compositor.CreateSpriteVisual();
_maskVisual.Brush = _maskBrush;
_maskVisual.Size = new Vector2(156, 156);
使用 NineGrid 拉伸的 CompositionBrush 來繪製
CompositionNineGridBrush 使用 CompositionBrush 來繪製一個區域,並透過九宮格隱喻來進行拉伸。 九宮格的概念可以讓你透過不同方式來拉伸 CompositionBrush 的邊緣和角落,而非它的中心。 九格拉伸的來源可以是任何類型的 CompositionBrush,例如 CompositionColorBrush、CompositionSurfaceBrush 或 CompositionEffectBrush。
以下程式碼示範了用 CompositionNineGridBrush 繪製的 SpriteVisual。 遮罩的來源是一個 CompositionSurfaceBrush,並透過 Nine-Grid 進行拉伸。
Compositor _compositor;
SpriteVisual _nineGridVisual;
CompositionNineGridBrush _nineGridBrush;
_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
_nineGridBrush = _compositor.CreateNineGridBrush();
// nineGridImage.png is 50x50 pixels; nine-grid insets, as measured relative to the actual size of the image, are: left = 1, top = 5, right = 10, bottom = 20 (in pixels)
LoadedImageSurface _imageSurface = LoadedImageSurface.StartLoadFromUri(new Uri("ms-appx:///Assets/nineGridImage.png"));
CompositionSurfaceBrush sourceBrush = _compositor.CreateSurfaceBrush(_imageSurface);
_nineGridBrush.Source = sourceBrush;
// Set nine-grid insets.
_nineGridBrush.SetInsets(1, 5, 10, 20);
// Set the appropriate stretch on the SurfaceBrush for the center of the nine-grid.
sourceBrush.Stretch = CompositionStretch.Fill;
_nineGridVisual = _compositor.CreateSpriteVisual();
_nineGridVisual.Brush = _nineGridBrush;
_nineGridVisual.Size = new Vector2(100, 75);
使用背景像素進行繪畫
CompositionBackdropBrush 使用區域後方的內容來繪製一個區域。 CompositionBackdropBrush 從不單獨使用,而是用作另一個 CompositionBrush 的輸入,比如 EffectBrush。 例如,您可以使用 CompositionBackdropBrush 來作為模糊效果的輸入,達成類似磨砂玻璃的效果。
以下程式碼展示了一個小型視覺樹,使用 CompositionSurfaceBrush 建立一個影像,並在影像上方添加一層磨砂玻璃覆蓋。 磨砂玻璃覆蓋層是透過在圖片上方放置填滿 EffectBrush 的 SpriteVisual 來製作的。 EffectBrush 使用 CompositionBackdropBrush 作為模糊效果的輸入。
Compositor _compositor;
ContainerVisual _containerVisual;
SpriteVisual _imageVisual;
SpriteVisual _backdropVisual;
_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
// Create a container visual to host the visual tree.
_containerVisual = _compositor.CreateContainerVisual();
// Create _imageVisual and add it to the bottom of the container visual.
CompositionSurfaceBrush _licoriceBrush = _compositor.CreateSurfaceBrush();
LoadedImageSurface loadedSurface = LoadedImageSurface.StartLoadFromUri(new Uri("ms-appx:///Assets/licorice.jpg"));
_licoriceBrush.Surface = loadedSurface;
_imageVisual = _compositor.CreateSpriteVisual();
_imageVisual.Brush = _licoriceBrush;
_imageVisual.Size = new Vector2(156, 156);
_imageVisual.Offset = new Vector3(0, 0, 0);
_containerVisual.Children.InsertAtBottom(_imageVisual);
// Create a SpriteVisual and add it to the top of the container visual.
// Paint the visual with an EffectBrush that applies blur to the content underneath it.
GaussianBlurEffect blurEffect = new GaussianBlurEffect()
{
Name = "Blur",
BlurAmount = 1.0f,
BorderMode = EffectBorderMode.Hard,
Source = new CompositionEffectSourceParameter("source")
};
CompositionEffectFactory blurEffectFactory = _compositor.CreateEffectFactory(blurEffect);
CompositionEffectBrush _backdropBrush = blurEffectFactory.CreateBrush();
// Create a BackdropBrush and bind it to the EffectSourceParameter source.
_backdropBrush.SetSourceParameter("source", _compositor.CreateBackdropBrush());
_backdropVisual = _compositor.CreateSpriteVisual();
_backdropVisual.Brush = _backdropBrush;
_backdropVisual.Size = new Vector2(78, 78);
_backdropVisual.Offset = new Vector3(39, 39, 0);
_containerVisual.Children.InsertAtTop(_backdropVisual);
組合畫筆
許多 CompositionBrush 會使用其他 CompositionBrush 作為輸入。 例如,使用 SetSourceParameter 方法可將另一個 CompositionBrush 設定為 CompositionEffectBrush 的輸入。 下表列出了 CompositionBrushes 支援的組合。 請注意,使用不支援的組合會拋出例外。
| 刷子 | EffectBrush.SetSourceParameter() | 遮罩筆刷.Mask | MaskBrush。來源 | NineGridBrush.Source |
|---|---|---|---|---|
| CompositionColorBrush | 是 | 是 | 是 | 是 |
| CompositionLinear 漸層筆刷 |
是 | 是 | 是 | [否] |
| 組成SurfaceBrush | 是 | 是 | 是 | 是 |
| 合成效果筆刷 | [否] | [否] | 是 | [否] |
| CompositionMaskBrush | [否] | [否] | [否] | [否] |
| CompositionNineGridBrush | 是 | 是 | 是 | [否] |
| 構圖背景畫筆 | 是 | [否] | [否] | [否] |
使用 XAML 筆刷與 CompositionBrush 之比較
下表列出了情境清單,以及在應用程式中繪製 UIElement 或 SpriteVisual 時,是否規定使用 XAML 或 Composition 畫筆。
備註
若建議使用 CompositionBrush 作為 XAML UIElement,則假設該 CompositionBrush 是使用 XamlCompositionBrushBase 封裝。
| 情境 | XAML UIElement | Composition SpriteVisual |
|---|---|---|
| 用純色來塗一個區域 | SolidColorBrush | CompositionColorBrush |
| 用動畫色彩繪製一個區域 | SolidColorBrush | CompositionColorBrush |
| 用靜態漸層來繪製一個區域 | 線性漸層筆刷 | 組合線性漸層畫筆 |
| 用動畫漸層停色來繪製一個區域 | 合成線性漸層畫筆 | Composition線性漸層筆刷 |
| 用圖像畫出一個區域 | ImageBrush | CompositionSurfaceBrush |
| 用網頁來繪製一個區域 | WebView2 | 不適用 |
| 使用九宮格伸縮法以圖像繪製區域 | 影像控制 | 組成九格刷 |
| 使用具動畫效果的 NineGrid 拉伸技術來繪製區域 | 組成九格刷 | 合成九宮格刷 |
| 使用交換鏈在區域上進行著色 | 交換鏈面板 | CompositionSurfaceBrush 與交換鏈互操作 |
| 用影片來繪製一個區域 | 媒體播放元件 | CompositionSurfaceBrush 與媒體互通 |
| 用自訂 2D 繪圖繪製一個區域 | Win2D 的 CanvasControl | CompositionSurfaceBrush 與 Win2D 互操作 |
| 用非動畫遮罩繪製區域 | 使用 XAML 形狀 來定義遮罩 | CompositionMaskBrush |
| 用動畫面罩繪製區域 | CompositionMaskBrush | CompositionMaskBrush |
| 用動畫濾鏡效果來繪製一個區域 | 合成效果筆刷 | 合成效果筆刷 |
| 在背景像素上塗上一個效果的區域 | Composition背景筆刷 | Composition背景筆刷 |