iOS TextKit中是否可获取字体替换相关信息?
在TextKit中获取字形替换的实际字体
当主字体缺少目标字形时,TextKit会自动通过字体级联逻辑匹配替代字体,要获取这个实际使用的字体,有两种可靠的实现路径:
方法1:直接通过NSLayoutManager查询字形属性
NSLayoutManager的textStorage(_:attributesForGlyphAt:effectiveRange:)方法可以返回指定字形所在范围的实际渲染属性,其中就包含了替换后的字体。系统在完成字形替换后,会将替代字体更新到对应字形范围的属性字典中。
示例代码(Swift):
// 假设你已经有NSLayoutManager实例(比如textView.layoutManager) let targetGlyphIndex = 5 // 你要查询的字形索引 var effectiveRange = NSRange(location: 0, length: 0) guard let textStorage = layoutManager.textStorage, let attributes = textStorage.attributes(forGlyphAt: targetGlyphIndex, effectiveRange: &effectiveRange) else { return } if let actualFont = attributes[.font] as? UIFont { print("实际渲染字体:\(actualFont.fontName),生效范围:\(effectiveRange)") }
方法2:结合CoreText的CTRun查询(贴近你熟悉的CTRun功能)
TextKit底层基于CoreText实现,你可以通过NSLayoutManager获取对应的CTLine,再遍历CTRun拿到每个字形对应的实际字体,这和CoreText中直接操作CTRun的逻辑完全一致。
示例代码(Swift):
let targetGlyphIndex = 5 var effectiveRange = NSRange(location: 0, length: 0) guard let ctLine = layoutManager.ctLine(forGlyphAt: targetGlyphIndex, effectiveRange: &effectiveRange) else { return } let runCount = CTLineGetGlyphCount(ctLine) for runIndex in 0..<runCount { let ctRun = CTLineGetRunAtIndex(ctLine, runIndex) let runGlyphRange = CTRunGetGlyphRange(ctRun) // 检查目标字形是否在当前CTRun的范围内 if targetGlyphIndex >= runGlyphRange.location && targetGlyphIndex < runGlyphRange.location + runGlyphRange.length { let runAttributes = CTRunGetAttributes(ctRun) as [CFString: Any] let ctFont = runAttributes[kCTFontAttributeName] as! CTFont let actualFont = UIFont(ctFont: ctFont) print("实际渲染字体:\(actualFont.fontName)") break } }
注意事项
- 必须确保NSLayoutManager已经完成布局操作,比如在
UITextView的layoutSubviews方法之后调用,或者监听NSLayoutManagerDelegate的layoutManager(_:didCompleteLayoutFor:textContainer:atEnd:)回调再执行查询,否则可能拿到未更新的属性。 effectiveRange参数会返回当前字体生效的连续字形范围,你可以通过它批量查询同一段使用替代字体的字形。
内容的提问来源于stack exchange,提问作者Céline
相关产品推荐
相关产品推荐

