我正在一个使用Markdown语法的Mac应用程序中开发一个富文本编辑器。我使用NSTextStorage在Markdown语法中监视匹配,然后将样式实时应用到NSAttributedString中,如下所示:

在这一点上,我已经在我的头上在这件事上,但我很高兴取得进展。) 本教程非常有用。。
作为下一步,我希望在呈现字符串时隐藏标记字符。因此,在上面的示例中,一旦输入了最后一个星号,我希望隐藏* *字符,并以粗体显示sample。
我使用的是NSLayoutManager委托,我可以看到匹配的字符串,但我不清楚如何使用shouldGenerateGlyphs方法生成修改后的符号/属性。到目前为止,我所拥有的是:
func layoutManager(_: NSLayoutManager, shouldGenerateGlyphs _: UnsafePointer<CGGlyph>, properties _: UnsafePointer<NSLayoutManager.GlyphProperty>, characterIndexes _: UnsafePointer<Int>, font _: NSFont, forGlyphRange glyphRange: NSRange) -> Int {
let pattern = "(\\*\\w+(\\s\\w+)*\\*)" // Look for stuff like *this*
do {
let regex = try NSRegularExpression(pattern: pattern)
regex.enumerateMatches(in: textView.string, range: glyphRange) {
match, _, _ in
// apply the style
if let matchRange = match?.range(at: 1) {
print(matchRange) <!-- This is the range of *sample*
// I am confused on how to provide the updated properties below...
// let newProps = NSLayoutManager.GlyphProperty.null
// layoutManager.setGlyphs(glyphs, properties: newProps, characterIndexes: charIndexes, font: aFont, forGlyphRange: glyphRange)
// return glyphRange.length
}
}
} catch {
print("\(error.localizedDescription)")
}
return 0
}如何根据我找到的隐藏星号的文本范围来修改传递给setGlyphs的内容?
发布于 2020-06-04 17:10:44
我决定提交另一个解决方案,因为这方面的信息很少,也许有人会发现它是有用的。一开始,我被layoutManager(_:shouldGenerateGlyphs:properties:characterIndexes:font:forGlyphRange:)完全搞糊涂了,直到我找到了纪尧姆·阿吉斯( Guillaume )非常彻底的解释(上图)。再加上25‘18英寸的幻灯片,进入2018年世界互联网大会演示版"TextKit最佳做法“,并研究不安全的指针是如何起作用的,这对我起了很大作用。
我的解决方案并不直接处理隐藏标记字符的问题,而是隐藏具有特定值(DisplayType.excluded)的自定义属性(DisplayType.excluded)的字符。(这正是我所需要的。)但是代码相当优雅,所以它可能很有教育意义。
以下是自定义属性定义:
extension NSAttributedString.Key { static let displayType = NSAttributedString.Key(rawValue: "displayType") }要进行检查,可以在视图控制器的ViewDidLoad (设置为NSLayoutManagerDelegate)中这样做:
textView.layoutManager.delegate = self
let text = NSMutableAttributedString(string: "This isn't easy!", attributes: [.font: UIFont.systemFont(ofSize: 24), .displayType: DisplayType.included])
let rangeToExclude = NSRange(location: 7, length: 3)
text.addAttribute(.displayType, value: DisplayType.excluded, range: rangeToExclude)
textView.attributedText = text最后,下面是完成所有工作的函数:
func layoutManager(_ layoutManager: NSLayoutManager, shouldGenerateGlyphs glyphs: UnsafePointer<CGGlyph>, properties props: UnsafePointer<NSLayoutManager.GlyphProperty>, characterIndexes charIndexes: UnsafePointer<Int>, font aFont: UIFont, forGlyphRange glyphRange: NSRange) -> Int {
// Make mutableProperties an optional to allow checking if it gets allocated
var mutableProperties: UnsafeMutablePointer<NSLayoutManager.GlyphProperty>? = nil
// Check the attributes value only at charIndexes.pointee, where this glyphRange begins
if let attribute = textView.textStorage.attribute(.displayType, at: charIndexes.pointee, effectiveRange: nil) as? DisplayType, attribute == .excluded {
// Allocate mutableProperties
mutableProperties = .allocate(capacity: glyphRange.length)
// Initialize each element of mutableProperties
for index in 0..<glyphRange.length { mutableProperties?[index] = .null }
}
// Update only if mutableProperties was allocated
if let mutableProperties = mutableProperties {
layoutManager.setGlyphs(glyphs, properties: mutableProperties, characterIndexes: charIndexes, font: aFont, forGlyphRange: glyphRange)
// Clean up this UnsafeMutablePointer
mutableProperties.deinitialize(count: glyphRange.length)
mutableProperties.deallocate()
return glyphRange.length
} else { return 0 }
}在字符和字形计数不匹配的情况下,上面的代码似乎很健壮:attribute(_:at:effectiveRange:)只使用charIndexes,mutableProperties只使用glyphRange。此外,由于mutableProperties在主函数中被赋予与props相同的类型(实际上,它是可变的和可选的),所以以后不需要转换它。
https://stackoverflow.com/questions/57467951
复制相似问题