以前用PointLight作了一個番茄鍾,效果還不錯,具體可見這篇文章:html
後來試玩了Win2D,此次就用Win2D實現文字的鏤空效果,配合PointLight作一個內斂不張揚的番茄鍾。github
實現鏤空文字的核心思想是使用CanvasGeometry.CreateText從TextLayout獲取一個Geometry,而後使用DrawGeometry將它畫到DrawingSurface。這篇文章介紹了具體的實現步驟。canvas
Win2D Gallery提供了大量Win2D的Sample,此次就參考了其中的文字鏤空效果例子,地址和運行效果以下:windows
Sample的代碼量雖多,其實核心並不複雜,下面講講須要用到的API:session
由於要用到Win2D,因此首先要引用Win2D.uwp nuget包。由於個人目標不是輸出到CanvasControl上,而是想要輸出到一個SpriteVisual上,因此使用CanvasDevice:app
var canvasDevice = CanvasDevice.GetSharedDevice();
複製代碼
而後建立一個Compositor,並將這個Compositor和CanvasDevice關聯起來,這裏須要使用 CanvasComposition 建立 GraphicsDevice:函數
var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
var graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(compositor, canvasDevice);
複製代碼
而後使用CompositionGraphicsDevice.CreateDrawingSurface建立一個CompositionDrawingSurface對象,它是用來繪畫內容的表面:動畫
var drawingSurface = graphicsDevice.CreateDrawingSurface(e.NewSize, DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);
複製代碼
使用Compositor.CreateSurfaceBrush建立一個CompositionSurfaceBrush
,它的做用是使用像素繪製SpriteVisual,簡單來講它就是一張位圖,而後輸出到SpriteVisual上:
var maskSurfaceBrush = compositor.CreateSurfaceBrush(drawingSurface);
spriteTextVisual.Brush = maskSurfaceBrush;
複製代碼
有了CompositionDrawingSurface就能夠隨心所欲了,將這個DrawingSurface做爲參數,調用CanvasComposition.CreateDrawingSession建立DrawingSession,DrawingSession提供了多個函數,能夠自由地在DrawingSurface上畫文字、形狀、圖片甚至SVG。
using (var session = CanvasComposition.CreateDrawingSession(drawingSurface))
{
}
複製代碼
要再DrawingSurface上寫字,須要CanvasTextLayout,而CanvasTextLayout中的文字大小、格式等則由CanvasTextFormat定義:
using (var textFormat = new CanvasTextFormat()
{
FontSize = (float)FontSize,
Direction = CanvasTextDirection.LeftToRightThenTopToBottom,
VerticalAlignment = CanvasVerticalAlignment.Center,
HorizontalAlignment = CanvasHorizontalAlignment.Center,
})
{
using (var textLayout = new CanvasTextLayout(session, Text, textFormat, width, height))
{
Color fontColor = FontColor;
session.DrawTextLayout(textLayout, 0, 0, fontColor);
}
}
複製代碼
由於個人目標是鏤空的文字,因此不能直接使用DrawTextLayout。這裏須要使用CanvasGeometry.CreateText從TextLayout獲取一個Geometry,而後使用DrawGeometry將它畫到DrawingSurface。CanvasStrokeStyle是可選的,它控制邊框的虛線。
using (var textGeometry = CanvasGeometry.CreateText(textLayout))
{
var dashedStroke = new CanvasStrokeStyle()
{
DashStyle = DashStyle
};
session.DrawGeometry(textGeometry, OutlineColor, (float)StrokeWidth, dashedStroke);
}
複製代碼
將上面的代碼總結一下,封裝爲一個OutlineTextControl 控件,它提供了Text、OutlineColor、FontColor等屬性,在控件SizeChanged時,或者各個屬性改變時調用DrawText
從新在CompositionDrawingSurface上繪製文字。代碼大體以下:
public class OutlineTextControl : Control
{
private CompositionDrawingSurface _drawingSurface;
public OutlineTextControl() {
var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
var graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(compositor, CanvasDevice.GetSharedDevice());
var spriteTextVisual = compositor.CreateSpriteVisual();
ElementCompositionPreview.SetElementChildVisual(this, spriteTextVisual);
SizeChanged += (s, e) =>
{
_drawingSurface = graphicsDevice.CreateDrawingSurface(e.NewSize, DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);
DrawText();
var maskSurfaceBrush = compositor.CreateSurfaceBrush(_drawingSurface);
spriteTextVisual.Brush = maskSurfaceBrush;
spriteTextVisual.Size = e.NewSize.ToVector2();
};
RegisterPropertyChangedCallback(FontSizeProperty, new DependencyPropertyChangedCallback((s, e) =>
{
DrawText();
}));
}
private void DrawText() {
if (ActualHeight == 0 || ActualWidth == 0 || string.IsNullOrWhiteSpace(Text) || _drawingSurface == null)
return;
var width = (float)ActualWidth;
var height = (float)ActualHeight;
using (var session = CanvasComposition.CreateDrawingSession(_drawingSurface))
{
session.Clear(Colors.Transparent);
using (var textFormat = new CanvasTextFormat()
{
FontSize = (float)FontSize,
Direction = CanvasTextDirection.LeftToRightThenTopToBottom,
VerticalAlignment = CanvasVerticalAlignment.Center,
HorizontalAlignment = CanvasHorizontalAlignment.Center,
})
{
using (var textLayout = new CanvasTextLayout(session, Text, textFormat, width, height))
{
if (ShowNonOutlineText)
{
session.DrawTextLayout(textLayout, 0, 0, FontColor);
}
using (var textGeometry = CanvasGeometry.CreateText(textLayout))
{
var dashedStroke = new CanvasStrokeStyle()
{
DashStyle = DashStyle
};
session.DrawGeometry(textGeometry, OutlineColor, (float)StrokeWidth, dashedStroke);
}
}
}
}
}
//SOME CODE AND PROPERTIES
}
複製代碼
文章開頭的那個番茄鍾源碼能夠在這裏查看:
OnePomodoro_OutlineTextView.xaml at master
也能夠安裝個人番茄鍾應用試玩一下,安裝地址:
CompositionGraphicsDevice Class (Windows.UI.Composition) - Windows UWP applications _ Microsoft Docs
CompositionDrawingSurface Class (Windows.UI.Composition) - Windows UWP applications _ Microsoft Docs
CompositionGraphicsDevice Class (Windows.UI.Composition) - Windows UWP applications _ Microsoft Docs
CompositionSurfaceBrush Class (Windows.UI.Composition) - Windows UWP applications _ Microsoft Docs