/ textview

使用 TextKit 定制全功能的 TextView —— RichTextView

在 iOS 7 之后,苹果提供了 TextKit 方便我们去定制文本的显示方式,虽然不如 CoreText 用起来可控性高(超强方案你可以查看此 YYText 这个类库),但是已经可以完成绝大部分你可能用到的定制。

如果你只是需要某一部分特性,不妨自己动手来完成,RichTextView 有以下特性

  • Mention
  • HashTag
  • URL
  • Email
  • Image
  • Custom
  • Placeholder
  • Interaction Delegate

支持多种常见类型,自定义类型的检测,插入图像,交互事件和文字样式的定制,那么接下来一起看下基本的实现原理。

image

自定义 NSTextStorage

RichTextView 主要的实现方式就是通过继承 NSTextStorage,在processEditing() 方法里,通过正则匹配,来给我们的文字进行处理。

例如 Metion 的处理,首先创建一个正则匹配

    //For Mention
    
    let mentionPattern = "@[^\\s::,,@]+$?"
    
    let mentionExpression = try? NSRegularExpression(pattern: mentionPattern, options: NSRegularExpressionOptions())

接着通过 NSRegularExpression 的 enumerateMatchesInString 方法对当前的文字进行匹配处理,将获取到的结果逐一进行处理

    if let mentionExpression = mentionExpression {

mentionExpression.enumerateMatchesInString(self.string, options: NSMatchingOptions(), range: paragraphRange, usingBlock: { (result, flags, stop) -> Void in
            
            if let result = result {
            }                
        })
    }

在处理的时候,就可以给这段文字增加自定义的样式和类型标记,通过加入 NSLinkAttributeName 可以使得这段文字原生支持 UITextView 的交互点击事件。

let textValue = (self.string as NSString).substringWithRange(result.range)
                
let textAttributes: [String : AnyObject]! = [NSForegroundColorAttributeName: UIColor.blueColor(), NSLinkAttributeName: textValue, RichTextViewDetectedDataHandlerAttributeName: DetectedDataType.Mention.rawValue]
                
self.addAttributes(textAttributes, range: result.range )
                
self.mentionRanges.append(result.range)

处理用户交互事件

这里的处理就较为简单了,在 Delegte 里当 UITextView 询问如何处理的时候,就会调用下面的方法

public func textView(textView: UITextView, shouldInteractWithURL URL: NSURL, inRange characterRange: NSRange) -> Bool {
}

此时便可以判断所交互的文字类型,并调用此类型的闭包。

图片处理

图片这里利用了 NSTextAttachment 来实现,思路也是相当的直接

    let attachment = NSTextAttachment(data: nil, ofType: nil)
    attachment.image = image
    attachment.bounds = CGRectMake(0, 0, size.width, size.height)

创建好 NSTextAttachment 后,基于 Attachment 新建一段 NSAttributedString,并加入自定义 addAttributes 方便我们在交互事件的处理

    if let attachmentAttributedString = NSAttributedString(attachment: attachment) as? NSMutableAttributedString {
        // sets the paragraph styling of the text attachment
        let attr: [String: AnyObject] = [NSParagraphStyleAttributeName: paragraphStyle(0), RichTextViewImageAttributeName: imageName, RichTextViewDetectedDataHandlerAttributeName: DetectedDataType.Image.rawValue]
        
        attachmentAttributedString.addAttributes(attr, range: NSRange(location: 0, length: attachmentAttributedString.length))
    }

NSLayoutManager

NSLayoutManager 的功能也相当强大,可以对排版和特效进行很多定制,RichTextView 的研究目前还没进行到 NSLayoutManager,如果你有兴趣,不妨来个 PR 吧!

使用 TextKit 定制全功能的 TextView —— RichTextView
Share this