2016-04-16 52 views
2

我将如何为制表符,空格和换行符绘制隐形字符UITextViewUITextView绘制隐形/空白字符

我想它必须在drawRect(CGRect)方法或由Text Kit中的布局管理器处理。任何简单和/或直观的解决方案?

我只需要知道如何获得每个空格字符的CGRect以及覆盖的哪种方法无缝地为每个空格字符绘制图形?

在此先感谢您的任何建议/帮助。
另外,我不介意你的答案在Objective-C中,尽管这两种语言都是首选。

+0

阅读苹果关于文本布局系统的文档。文本编辑不是一个简单的主题,涉及到很多类,如NSLayoutManager,NSTextView,NSTextContainer,NSTypeSetter。已经有一段时间了,但你可能需要一个自定义的NSLayoutManager(在iOS上)或一个自定义的NSTypeSetter(在OS X上)。 用自定义(可见)字符替换不可见字符当然是可行的,但它不像在NSTextView中重写drawRect那么简单。 – user965972

+0

@ user965972我已经有了一个自定义的NSLayoutManager和自定义的NSTextStorage,它为文本视图启用行编号和压缩行的缩进。我对Text Kit非常熟悉,但是我希望有人能够给我一个提示,告诉我在生产中用于自定义绘制空白字符图形的最可接受的做法 –

+0

在这种情况下:布局管理器具有从字符生成NSGlyphs的功能(尽管这不是一对一的关系)。重写其中一个函数来为自定义的NSGlyph注入一个空格字符。 你不必自己做任何绘画。您只需指定文字系统应绘制哪个字形。 – user965972

回答

1

我发现比NSLayoutManagershowsInvisibleCharacters属性设置为true,通过继承NSLayoutManager和覆盖方法drawBackgroundForGlyphRange(NSRange, CGPoint),这允许针对每个空白字符定制附图中,例如更好的解决方案:

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) 
      } 

     } 

    } 

}