IOS开发入门iOS 开发 富文本详解之TextKit详解
白羽 2019-04-16 来源 :网络 阅读 533 评论 0

摘要:本文将带你了解IOS开发入门iOS 开发 富文本详解之TextKit详解,希望本文对大家学IOS有所帮助。

    本文将带你了解IOS开发入门iOS 开发 富文本详解之TextKit详解,希望本文对大家学IOS有所帮助。


IOS开发入门iOS 开发 富文本详解之TextKit详解


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 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<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    }}</uitouch>    

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之IOS频道!

本文由 @白羽 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程