Xamarin.iOS 中的 TextKit
TextKit 是新的 API,可提供強大的文字配置和轉譯功能。 它是建置在低階核心文字架構之上,但比核心文字更容易使用。
若要讓 TextKit 的功能可供標準控件使用,已重新實作數個 iOS 文字控制項以使用 TextKit,包括:
- UITextView
- UITextField
- UILabel
架構
TextKit 提供分層架構,將文字記憶體與配置和顯示區隔開,包括下列類別:
NSTextContainer
– 提供用來配置文字的座標系統和幾何。NSLayoutManager
– 將文字轉換成字元來配置文字。NSTextStorage
– 保存文字數據,以及處理批次文字屬性更新。 任何批次更新會交給配置管理員以實際處理變更,例如重新計算版面配置和重新繪製文字。
這三個類別會套用至轉譯文字的檢視。 內建的文字處理檢視,例如 UITextView
、 UITextField
和 UILabel
已經設定這些檢視,但您也可以建立並套用至任何 UIView
實例。
下圖說明此架構:
文字 儲存體 和屬性
類別 NSTextStorage
會保存檢視所顯示的文字。 它也會將任何變更傳達給要顯示的版面配置管理員,例如字元或其屬性的變更。 NSTextStorage
繼承自MSMutableAttributed
字串,允許在和 EndEditing
呼叫之間BeginEditing
批次指定文字屬性的變更。
例如,下列代碼段會分別指定前景和背景色彩的變更,以及以特定範圍為目標:
textView.TextStorage.BeginEditing ();
textView.TextStorage.AddAttribute(UIStringAttributeKey.ForegroundColor, UIColor.Green, new NSRange(200, 400));
textView.TextStorage.AddAttribute(UIStringAttributeKey.BackgroundColor, UIColor.Black, new NSRange(210, 300));
textView.TextStorage.EndEditing ();
呼叫 之後 EndEditing
,變更會傳送至版面配置管理員,進而執行任何必要的配置和轉譯計算,讓檢視中顯示的文字。
具有排除路徑的版面配置
TextKit 也支援版面配置,並允許複雜的案例,例如多欄文字和在稱為 排除路徑的指定路徑周圍流動文字。 排除路徑會套用至文字容器,此容器會修改文字配置幾何,導致文字在指定的路徑周圍流動。
新增排除路徑需要設定 ExclusionPaths
配置管理員上的屬性。 設定此屬性會使版面配置管理員使文字版面配置失效,並在排除路徑周圍流動文字。
根據 CGPath 排除
請考慮下列 UITextView
子類別實作:
public class ExclusionPathView : UITextView
{
CGPath exclusionPath;
CGPoint initialPoint;
CGPoint latestPoint;
UIBezierPath bezierPath;
public ExclusionPathView (string text)
{
Text = text;
ContentInset = new UIEdgeInsets (20, 0, 0, 0);
BackgroundColor = UIColor.White;
exclusionPath = new CGPath ();
bezierPath = UIBezierPath.Create ();
LayoutManager.AllowsNonContiguousLayout = false;
}
public override void TouchesBegan (NSSet touches, UIEvent evt)
{
base.TouchesBegan (touches, evt);
var touch = touches.AnyObject as UITouch;
if (touch != null) {
initialPoint = touch.LocationInView (this);
}
}
public override void TouchesMoved (NSSet touches, UIEvent evt)
{
base.TouchesMoved (touches, evt);
UITouch touch = touches.AnyObject as UITouch;
if (touch != null) {
latestPoint = touch.LocationInView (this);
SetNeedsDisplay ();
}
}
public override void TouchesEnded (NSSet touches, UIEvent evt)
{
base.TouchesEnded (touches, evt);
bezierPath.CGPath = exclusionPath;
TextContainer.ExclusionPaths = new UIBezierPath[] { bezierPath };
}
public override void Draw (CGRect rect)
{
base.Draw (rect);
if (!initialPoint.IsEmpty) {
using (var g = UIGraphics.GetCurrentContext ()) {
g.SetLineWidth (4);
UIColor.Blue.SetStroke ();
if (exclusionPath.IsEmpty) {
exclusionPath.AddLines (new CGPoint[] { initialPoint, latestPoint });
} else {
exclusionPath.AddLineToPoint (latestPoint);
}
g.AddPath (exclusionPath);
g.DrawPath (CGPathDrawingMode.Stroke);
}
}
}
}
此程式代碼會新增使用核心圖形在文字檢視上繪製的支援。 由於 類別 UITextView
現在建置成使用 TextKit 進行文字轉譯和版面配置,因此可以使用 TextKit 的所有功能,例如設定排除路徑。
重要
此範例子類別 UITextView
可新增觸控繪圖支援。 不需要子類別化 UITextView
,即可取得 TextKit 的功能。
在使用者繪製文字檢視之後,繪製CGPath
會藉由設定 UIBezierPath.CGPath
屬性來套用至 UIBezierPath
實例:
bezierPath.CGPath = exclusionPath;
更新下列程式代碼列會讓文字版面設定在路徑周圍更新:
TextContainer.ExclusionPaths = new UIBezierPath[] { bezierPath };
下列螢幕快照說明文字版面配置如何變更,以繞著繪製路徑流動:
請注意,在此案例中,配置管理員的 AllowsNonContiguousLayout
屬性會設定為 false。 這會導致針對文字變更的所有情況重新計算版面配置。 將此設定為 true 可能會避免完整版面配置重新整理來提升效能,特別是在大型檔時。 不過,將 設定 AllowsNonContiguousLayout
為 true 會防止排除路徑在某些情況下更新版面配置,例如,如果在運行時間輸入文字,但在設定路徑之前沒有尾端歸位字元。