iOS 开发 富文本详解之TextKit详解
来源:互联网 发布:网络五层模型每层功能 编辑:程序博客网 时间:2024/06/08 22:13
textkit结构
textkit使用步骤
#Mark - 1. 自定义label --class CZLabel: UILabel---四个属性//1.属性文本存储private lazy var textStorage = NSTextStorage()//2.负责文本字形布局对象private lazy var layoutManager = NSLayoutManager()//3.设定文本绘制的范围private lazy var textContainer = NSTextContainer()//4.属性数组,保存匹配的范围private lazy var linkRanges = [NSRange]()#Mark - 2. 重新init方法-- override init(frame: CGRect) {}//0.开启用户交互userInteractionEnabled = true//1.textStorage接管label的属性if let attributedText = attributedText {}//2.设置对象关系textStorage.addLayoutManager(layoutManager)layoutManager.addTextContainer(textContainer)#Mark - 3. 外界给label的text属性赋值 label.text = @"@好友,#健康#,....."//重写属性的text方法--一旦label里的内容发生变化,就可以让textStorage相应变化//1.段落处理--1.范围 2.属性 3.段落样式let attrStringM = addLineBreak(attributedText!)//2.正则匹配--1.清空原有 2.匹配范围 3.创建正则 4.匹配 5.遍历匹配结果,添加到属性数组regexLinkRanges(attrStringM)//3.连接颜色设置---1.范围 2.属性 3.添加颜色 4.遍历属性数组,改变颜色addLinkAttribute(attrStringM)//4.添加到textStoragetextStorage.setAttributedString(attrStringM)//5.重新绘制setNeedsDisplay()#Mark - 4. textStorage字形和属性发生变化时,通知NSLayoutManager重新布局文本//MARK:3.设置布局--制定文本绘制区域override func layoutSubviews() { super.layoutSubviews() //制定文本绘制区域 textContainer.size = bounds.size}#Mark - 5. 绘制textStorage的文本内容--不能调用superoverride func drawTextInRect(rect: CGRect) { let range = NSMakeRange(0, textStorage.length) //Glyphs--字形---CGPoint()从原点绘制,也就是右上角 layoutManager.drawGlyphsForGlyphRange(range, atPoint: CGPoint(x: 0,y: 0))}#Mark - 6. 用户点击事件交互//0.懒加载@ # URL的匹配的正则法则 三个属性数组三步法:1.正则表达式 2.创建正则 3.匹配 4.便利匹配结果,添加到属性数组 //1.获取用户点击的位置let location = touches.first?.locationInView(self)//2.获取当前点中字符的索引let index = layoutManager.glyphIndexForPoint(location, inTextContainer: textContainer)//3.判断index在哪个标记的range 范围上for range in atRange ?? [] { if NSLocationInRange(index, range) { let strSub = (textStorage.string as NSString).substringWithRange(range) //进行结果处理 }}
Swift使用
import UIKitclass ZYLabel: UILabel { //attributedText富文本 //MARK:2.重写属性text方法,可以在ViewController里给文本赋值 //一旦label里的内容发生变化,就可以让textStorage相应变化 override var text:String? { didSet { if attributedText == nil { return } //换行处理属性 let attrStringM = addLineBreak(attributedText!) //换行后进行--正则匹配 regexLinkRanges(attrStringM) //换行后进行--连接颜色设置 addLinkAttribute(attrStringM) //添加到textStorage textStorage.setAttributedString(attrStringM) //重新绘制 setNeedsDisplay() } } ///MARK: textKit的三个核心对象 //属性文本存储 private lazy var textStorage = NSTextStorage() //负责文本字形布局对象 private lazy var layoutManager = NSLayoutManager() //设定文本绘制的范围 private lazy var textContainer = NSTextContainer() private lazy var linkRanges = [NSRange]() //纯代码接管Label override init(frame: CGRect) { super.init(frame: frame) //0.开启用户交互 userInteractionEnabled = true //1.textStorage接管label的属性 if let attributedText = attributedText { //如果原有文本设置了attribute textStorage.setAttributedString(attributedText) }else if let text = text { //如果原有文本没有设置attribute textStorage.setAttributedString(NSAttributedString(string: text)) }else { //如果原有文本为nil textStorage.setAttributedString(NSAttributedString(string: "")) } //2.设置对象关系 textStorage.addLayoutManager(layoutManager) layoutManager.addTextContainer(textContainer) } //MARK:1.Xib接管Label required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) //0.开启用户交互 userInteractionEnabled = true //1.准备文本内容---textStorage接管label的内容 if let attributedText = attributedText { //如果原有文本有attribute属性 textStorage.setAttributedString(attributedText) }else if let text = text { //如果原有文本没有attribute属性 textStorage.setAttributedString(NSAttributedString(string: text)) }else { //如果原有文本属性为nil textStorage.setAttributedString(NSAttributedString(string: "")) } //2.设置对象关系 textStorage.addLayoutManager(layoutManager) layoutManager.addTextContainer(textContainer) } /// MARK:2.1.段落样式处理 private func addLineBreak(attrString: NSAttributedString) -> NSMutableAttributedString { let attrStringM = NSMutableAttributedString(attributedString: attrString) if attrStringM.length == 0 { return attrStringM } //从(0,0)点开始,也就是从text的第一个字符开始 var range = NSRange(location: 0, length: 0) var attributes = attrStringM.attributesAtIndex(0, effectiveRange: &range) var paragraphStyle = attributes[NSParagraphStyleAttributeName] as? NSMutableParagraphStyle //设置段落样式--以字符分割,不以单词分割 if paragraphStyle != nil { //ByWordWrapping//按照单词分割换行,保证换行时的单词完整。 //ByCharWrapping按照字母换行,可能会在换行时将某个单词拆分到两行 paragraphStyle!.lineBreakMode = NSLineBreakMode.ByCharWrapping } else { // iOS 8.0 不能直接获取段落的样式 paragraphStyle = NSMutableParagraphStyle() paragraphStyle!.lineBreakMode = NSLineBreakMode.ByCharWrapping attributes[NSParagraphStyleAttributeName] = paragraphStyle attrStringM.setAttributes(attributes, range: range) } return attrStringM } /// MARK:2.2.连接的attribute的颜色设置 private func addLinkAttribute(attrStringM: NSMutableAttributedString) { if attrStringM.length == 0 { return } var range = NSRange(location: 0, length: 0) var attributes = attrStringM.attributesAtIndex(0, effectiveRange: &range) attrStringM.addAttributes(attributes, range: range) attributes[NSForegroundColorAttributeName] = UIColor.blueColor() for range in linkRanges { attrStringM.setAttributes(attributes, range: range) } } /// MARK:2.3.正则法则--匹配所有连接颜色:URL,#话题#,@好友---放到一个数组里 private let patterns = ["((http[s]{0,1}|ftp)://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:[a-zA-Z0-9]{3}_/=<>]*)?)|(www.[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)", "#.*?#", "@[\\u4e00-\\u9fa5a-zA-Z0-9_-]*"] private func regexLinkRanges(attrString: NSAttributedString) { //存储所有的匹配结果前,将原来的清空 linkRanges.removeAll() //正则匹配范围--整个label let regexRange = NSRange(location: 0, length: attrString.string.characters.count) for pattern in patterns { //创建正则 let regex = try! NSRegularExpression(pattern: pattern, options: .DotMatchesLineSeparators) //匹配 let results = regex.matchesInString(attrString.string, options:NSMatchingOptions(rawValue: 0) , range: regexRange) for range in results { //每一种正则法则可能匹配到多个符合要求的对象如@张三 @李四 匹配到两个,结果是个数组 linkRanges.append(range.rangeAtIndex(0)) } } } //MARK:3.设置布局--制定文本绘制区域 override func layoutSubviews() { super.layoutSubviews() //制定文本绘制区域 textContainer.size = bounds.size } //MARK:4.绘制textStorage的文本内容--不能调用super override func drawTextInRect(rect: CGRect) { let range = NSMakeRange(0, textStorage.length) //Glyphs--字形---CGPoint()从原点绘制,也就是右上角 layoutManager.drawGlyphsForGlyphRange(range, atPoint: CGPoint(x: 0,y: 0)) } //MARK:5.用户点击事件交互--处理不同匹配内容天转到不同界面 override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { //1.获取用户点击的位置--let location: CGPoint? guard let location = touches.first?.locationInView(self) else { return } //获取当前点中字符的索引 let index = layoutManager.glyphIndexForPoint(location, inTextContainer: textContainer) //判断index在哪个标记的range 范围上 for range in atRange ?? [] { if NSLocationInRange(index, range) { let strSub = (textStorage.string as NSString).substringWithRange(range) print(strSub) } } for range in jingRange ?? [] { if NSLocationInRange(index, range) { let strSub = (textStorage.string as NSString).substringWithRange(range) print(strSub) } } for range in urlRange ?? [] { if NSLocationInRange(index, range) { let strSub = (textStorage.string as NSString).substringWithRange(range) NSNotificationCenter.defaultCenter().postNotificationName("webView", object: self, userInfo: ["urlString":strSub]) } } }}//MARK: 正则表达式处理结果extension ZYLabel { //返回textStorage中的@肝健康公益 的range数组 var atRange:[NSRange]? { //正则表达式--@好友 let pattern = "@[\u{4e00}-\u{9fa5}]{0,}" guard let regx = try? NSRegularExpression(pattern: pattern, options: []) else { return nil } //多重匹配--//let matchs: [NSTextCheckingResult] let matchs = regx.matchesInString(textStorage.string, options: [], range: NSRange(location: 0,length: textStorage.length)) //遍历数组 var ranges = [NSRange]() for match in matchs { ranges.append(match.rangeAtIndex(0)) } return ranges } //返回textStorage中的话题## 的range数组 var jingRange:[NSRange]? { //正则表达式 let pattern = "#[\u{4e00}-\u{9fa5}]{0,}#" guard let regx = try? NSRegularExpression(pattern: pattern, options: []) else { return nil } //多重匹配--//let matchs: [NSTextCheckingResult] let matchs = regx.matchesInString(textStorage.string, options: [], range: NSRange(location: 0,length: textStorage.length)) //遍历数组 var ranges = [NSRange]() for match in matchs { ranges.append(match.rangeAtIndex(0)) } return ranges } //返回textStorage中的URL网址的range数组 var urlRange:[NSRange]? { //正则表达式 let pattern = "((http[s]{0,1}|ftp)://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:[a-zA-Z0-9_/=<>]]*)?)|(www.[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)" guard let regx = try? NSRegularExpression(pattern: pattern, options: []) else { return nil } //多重匹配--//let matchs: [NSTextCheckingResult] let matchs = regx.matchesInString(textStorage.string, options: [], range: NSRange(location: 0,length: textStorage.length)) //遍历数组 var ranges = [NSRange]() for match in matchs { ranges.append(match.rangeAtIndex(0)) } return ranges }}
0 0
- iOS 开发 富文本详解之TextKit详解
- iOS 富文本(NSMutableAttributedString)详解
- iOS富文本字符串AttributedString详解
- iOS: 富文本AttributedString的详解
- iOS富文本字符串AttributedString详解
- iOS中的富文本技术(1)-TextKit简介
- iOS中的富文本技术(1)-TextKit简介
- iOS开发之UILabel(富文本)
- iOS开发- OC之富文本
- iOS开发笔记之NSMutableAttributeString富文本
- OHAttributedLabel 富文本详解
- 富文本Attributes详解
- NSAttributedString 富文本详解
- Unity富文本详解
- iOS之文本处理框架TextKit介绍
- ios开发 富文本
- iOS 开发 富文本
- iOS之富文本
- Android NestedScrolling机制完全解析 带你玩转嵌套滑动
- CODEVS 1010 过河卒(棋盘型DP)
- Vue.js和MVVM的小细节
- Java中switch接受的几种数据类型
- 深入gradle
- iOS 开发 富文本详解之TextKit详解
- 设计模式(一)----简单工厂、工厂方法和抽象工厂区别
- JS模块化工具requirejs
- org.hibernate.MappingException: Unknown entity:
- 【Java每日一题】20161130
- MYSQL 索引类型、什么情况下用不上索引、什么情况下不推荐使用索引
- eclipse远程调试Tomcat方法(测试成功并且说说遇到的坑)
- 利用微信jssdk上传图片,并保存到本地
- oracle 常见错误码errorcode