2016-04-16 34 views
2

UITextViewは、タブ、スペース、改行の終わりにどのように非表示の文字を描画しますか?UITextView描画不可視/空白文字

drawRect(CGRect)メソッドで処理するか、テキストキットのレイアウトマネージャで処理する必要があります。シンプルかつ/または直感的なソリューションですか?

各空白文字のCGRectを取得する方法と、空白文字ごとにグラフィックをシームレスに描画する方法を知りたいだけですか?

事前にアドバイスをお願いします。
また、両方の言語が優先されることはありますが、objective-cでの回答があるかどうかは気にしません。

+0

リンゴを読みますテキストレイアウトシステムに関する文書。テキストの編集は簡単な話題ではなく、NSLayoutManager、NSTextView、NSTextContainer、NSTypeSetterなど多くのクラスがあります。それはしばらくしていますが、カスタムNSLayoutManager(iOSの場合)またはカスタムNSTypeSetter(OS Xの場合)が必要になる場合があります。 不可視の文字をカスタム(可視)文字で置き換えることは可能ですが、NSTextViewのdrawRectをオーバーライドするほど簡単ではありません。 – user965972

+0

@ user965972私は既にカスタムのNSLayoutManagerとカスタムNSTextStorageを持っていて、テキストビューの行番号と行のインデントを有効にしています。私はText Kitをよく知っていますが、空白文字グラフィックスでカスタム描画するために、プロダクションで使用される最も受け入れられる方法についてのヒントを教えてくれることを願っています –

+0

その場合:レイアウトマネージャは文字からNSGlyphsを生成する関数を持っていますそれは1対1の関係ではない)。これらの関数の1つをオーバーライドして、カスタムNSGlyphを空白文字に挿入します。 自分で描画する必要はありません。テキストシステムで描画するグリフを指定するだけで済みます。 – user965972

答えて

1

私はNSLayoutManagerをサブクラス化し、例えば、各空白文字のためのカスタム図面が可能になります方法drawBackgroundForGlyphRange(NSRange, CGPoint)をオーバーライドすることによって、trueNSLayoutManagershowsInvisibleCharactersプロパティを設定するよりも、より良い解決策を見つけた:

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

     } 

    } 

}