UITextView 绘制 Invisible/Whitespace 个字符
UITextView Draw Invisible/Whitespace Characters
如何让 UITextView
为制表符、空格和换行符结尾绘制不可见字符?
我认为它必须在 drawRect(CGRect)
方法中或由 Text Kit 中的布局管理器处理。任何简单 and/or 直观的解决方案?
我只需要知道如何获取每个空白字符的 CGRect
以及哪种覆盖方法可以无缝地为每个空白字符绘制图形?
提前感谢任何advice/help。
另外,我不介意你的回答是 objective-c,尽管两种语言都是首选。
我找到了一个比将 NSLayoutManager
的 showsInvisibleCharacters
属性 设置为 true
更好的解决方案,方法是子类化 NSLayoutManager
并重写方法 [=15] =],它允许为每个空白字符自定义绘图,例如:
class LayoutManager : NSLayoutManager {
var text: String? { return textStorage?.string }
var font: UIFont = UIFont.systemFontOfSize(UIFont.systemFontSize()) {
didSet {
guard let text = self.text else { return }
let textRange = NSMakeRange(0, (text as NSString).length)
invalidateGlyphsForCharactersInRange(textRange, actualCharacterRange: nil)
invalidateCharacterAttributesForCharactersInRange(textRange, actualCharacterRange: nil)
}
}
override func drawBackgroundForGlyphRange(glyphsToShow: NSRange, atPoint origin: CGPoint) {
super.drawBackgroundForGlyphRange(glyphsToShow, atPoint:origin)
guard let text = self.text else { return }
enumerateLineFragmentsForGlyphRange(glyphsToShow)
{ (rect: CGRect, usedRect: CGRect, textContainer: NSTextContainer, glyphRange: NSRange, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
let characterRange = self.characterRangeForGlyphRange(glyphRange, actualGlyphRange: nil)
// Draw invisible tab space characters
let line = (self.text as NSString).substringWithRange(characterRange)
do {
let expr = try NSRegularExpression(pattern: "\t", options: [])
expr.enumerateMatchesInString(line, options: [.ReportProgress], range: line.range)
{ (result: NSTextCheckingResult?, flags: NSMatchingFlags, stop: UnsafeMutablePointer<ObjCBool>) in
if let result = result {
let range = NSMakeRange(result.range.location + characterRange.location, result.range.length)
let characterRect = self.boundingRectForGlyphRange(range, inTextContainer: textContainer)
let symbol = "\u{21E5}"
let attrs = [NSFontAttributeName : Font]
let height = (symbol as NSString).sizeWithAttributes(attrs).height
symbol.drawInRect(CGRectOffset(characterRect, 1.0, height * 0.5, withAttributes: attrs)
}
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
}
}
如何让 UITextView
为制表符、空格和换行符结尾绘制不可见字符?
我认为它必须在 drawRect(CGRect)
方法中或由 Text Kit 中的布局管理器处理。任何简单 and/or 直观的解决方案?
我只需要知道如何获取每个空白字符的 CGRect
以及哪种覆盖方法可以无缝地为每个空白字符绘制图形?
提前感谢任何advice/help。
另外,我不介意你的回答是 objective-c,尽管两种语言都是首选。
我找到了一个比将 NSLayoutManager
的 showsInvisibleCharacters
属性 设置为 true
更好的解决方案,方法是子类化 NSLayoutManager
并重写方法 [=15] =],它允许为每个空白字符自定义绘图,例如:
class LayoutManager : NSLayoutManager {
var text: String? { return textStorage?.string }
var font: UIFont = UIFont.systemFontOfSize(UIFont.systemFontSize()) {
didSet {
guard let text = self.text else { return }
let textRange = NSMakeRange(0, (text as NSString).length)
invalidateGlyphsForCharactersInRange(textRange, actualCharacterRange: nil)
invalidateCharacterAttributesForCharactersInRange(textRange, actualCharacterRange: nil)
}
}
override func drawBackgroundForGlyphRange(glyphsToShow: NSRange, atPoint origin: CGPoint) {
super.drawBackgroundForGlyphRange(glyphsToShow, atPoint:origin)
guard let text = self.text else { return }
enumerateLineFragmentsForGlyphRange(glyphsToShow)
{ (rect: CGRect, usedRect: CGRect, textContainer: NSTextContainer, glyphRange: NSRange, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
let characterRange = self.characterRangeForGlyphRange(glyphRange, actualGlyphRange: nil)
// Draw invisible tab space characters
let line = (self.text as NSString).substringWithRange(characterRange)
do {
let expr = try NSRegularExpression(pattern: "\t", options: [])
expr.enumerateMatchesInString(line, options: [.ReportProgress], range: line.range)
{ (result: NSTextCheckingResult?, flags: NSMatchingFlags, stop: UnsafeMutablePointer<ObjCBool>) in
if let result = result {
let range = NSMakeRange(result.range.location + characterRange.location, result.range.length)
let characterRect = self.boundingRectForGlyphRange(range, inTextContainer: textContainer)
let symbol = "\u{21E5}"
let attrs = [NSFontAttributeName : Font]
let height = (symbol as NSString).sizeWithAttributes(attrs).height
symbol.drawInRect(CGRectOffset(characterRect, 1.0, height * 0.5, withAttributes: attrs)
}
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
}
}