在 iOS 7 之后,苹果提供了 TextKit 方便我们去定制文本的显示方式,虽然不如 CoreText 用起来可控性高(超强方案你可以查看此 YYText 这个类库),但是已经可以完成绝大部分你可能用到的定制。
如果你只是需要某一部分特性,不妨自己动手来完成, RichTextView 有以下特性
支持多种常见类型,自定义类型的检测,插入图像,交互事件和文字样式的定制,那么接下来一起看下基本的实现原理。
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 的功能也相当强大,可以对排版和特效进行很多定制,RichTextView 的研究目前还没进行到 NSLayoutManager,如果你有兴趣,不妨来个 PR 吧!