王小西,都市外乡人全集,www.hudong.cc
#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.添加到textstorage textstorage.setattributedstring(attrstringm) //5.重新绘制 setneedsdisplay() #mark - 4. textstorage字形和属性发生变化时,通知nslayoutmanager重新布局文本 //mark:3.设置布局--制定文本绘制区域 override func layoutsubviews() { super.layoutsubviews() //制定文本绘制区域 textcontainer.size = bounds.size } #mark - 5. 绘制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 - 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) //进行结果处理 } }
import uikit class 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, 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 } }
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
网友评论