[WPF] 如何實現文字描邊
- 2022 年 3 月 20 日
- 筆記
- Design and Animation, WPF
1. 前言
WPF 的 TextBlock 提供了大部分常用的文字修飾方法,在日常使用中基本夠用。如果需要更豐富的表現方式,WPF 也提供了其它用起來複雜一些的工具去實現這些需求。例如這篇文章介紹的文字描邊,就有幾種方法可以在 WPF 中呈現。這篇文章將簡單介紹這實現文字描邊的方法。
2. 將文字轉換位 Geometry
實現文字描邊的關鍵是使用 FormattedText 將文字轉換為 Geometry,然後通過其它技術將 Geometry 加上邊框再畫出來。
在 WPF 中,Geometry 及它的派生類(EllipseGeometry、LineGeometry、PathGeometry、RectangleGeometry 等)用於描述 2D 形狀的集合圖形。而 FormattedText 的 BuildGeometry
函數可以將文字轉換為 GeometryGroup(表示由其他 Geometry 對象組成的複合幾何圖形),程式碼如下:
private Geometry CreateTextGeometry()
{
// Create the formatted text based on the properties set.
FormattedText formattedText = new FormattedText(
Text,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface(
FontFamily,
FontStyle,
FontWeight,
FontStretch),
FontSize,
System.Windows.Media.Brushes.Black,// This brush does not matter since we use the geometry of the text.
100);
// Build the geometry object that represents the text.
return formattedText.BuildGeometry(new Point(0, 0));
}
得到 Geometry 後,有兩種方式將它畫出來。
3. 使用 DrawingContext
WPF 中的 DrawingContext 是一個基礎的繪圖對象,用於繪製各種圖形,它的一個最簡單的使用方式是重載 UIElement 的 OnRender 方法,在這個方法中繪製 UIElement 的UI:
// Override the OnRender call to add a Background and Border to the OffSetPanel
protected override void OnRender(DrawingContext dc)
{
SolidColorBrush mySolidColorBrush = new SolidColorBrush();
mySolidColorBrush.Color = Colors.LimeGreen;
Pen myPen = new Pen(Brushes.Blue, 10);
Rect myRect = new Rect(0, 0, 500, 500);
dc.DrawRectangle(mySolidColorBrush, myPen, myRect);
}
上面的示例程式碼用 DrawingContext 畫了一個500 * 500 的正方形。除了正方形,DrawingContext 還提供了 DrawEllipse、DrawImage、DrawLine 等函數,用於畫圓形、影像、線條等,也可以用 DrawText 函數畫出文字。不過比起直接用 DrawText,DrawGeometry 會是一個更好的選擇,因為它可以畫出文字的邊框。在上面的程式碼中我們已經將文字轉為一個 Geometry,接下來直接調用 DrawGeometry 並加上邊框:
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
var geometry = CreateTextGeometry();
// Draw the outline based on the properties that are set.
drawingContext.DrawGeometry(Foreground, new Pen(Stroke, StrokeThickness), geometry);
}
通過 Stroke, StrokeThickness 控制可以控制文字邊框的顏色和粗細。
4. 自定義 Shape
前面介紹的方法來自微軟的 示例文檔,不過既然都拿到文字的 Geometry 了,直接做成自定義的 Shape 不更好嗎,Shape 還可以很簡單地玩更多花樣更多動畫。用自定義 Shape 做空心文字的程式碼大致如下(省略了一些文本的自定義依賴屬性):
public class TextShape : Shape
{
private double _height;
private double _width;
private Geometry _textGeometry;
[Localizability(LocalizationCategory.Text)]
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
protected sealed override Geometry DefiningGeometry
{
get
{
return _textGeometry ?? Geometry.Empty;
}
}
protected override Size MeasureOverride(Size availableSize)
{
this.RealizeGeometry();
return new Size(Math.Min(availableSize.Width, _width), Math.Min(availableSize.Height, _height));
}
private void RealizeGeometry()
{
var formattedText = new FormattedText(
Text,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface(FontFamily, FontStyle, FontWeight, FontStretch), FontSize, Brushes.Black, 100);
_height = formattedText.Height;
_width = formattedText.Width;
_textGeometry = formattedText.BuildGeometry(new Point());
}
}
得到一個由文字轉換成的 Shape 後除了可以實現文字描邊,還可以玩很多動畫,例如下面這種:
5. 最後
這篇文章介紹了如何實現文字描邊。除了文字描邊,文章里介紹的文字轉換成 Shape 還有很多中玩法,下一篇文章將簡單試試其中一些。
另外,文字描邊的方案還可以參考部落格園的這篇部落格,將文本字元串用GDI+生成Bitmap,然後轉成BitmapImage:
6. 參考
Geometry 概述 – WPF .NET Framework
GeometryGroup 類 (System.Windows.Media)
FormattedText 類 (System.Windows.Media)
DrawingContext 類 (System.Windows.Media)
UIElement.OnRender(DrawingContext) 方法 (System.Windows)
7. 源碼
//github.com/DinoChan/wpf_design_and_animation_lab