博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
coretext简单使用
阅读量:6497 次
发布时间:2019-06-24

本文共 6021 字,大约阅读时间需要 20 分钟。

相对于UIKit,使用coretext绘制文本效率高,具有更高的自由度,可随时插入图片,增加文本点击事件等。

1.增加文本的点击事件

思路:定义UILabel子类,设置可点击的富文本range及其他属性(颜色、字体),touchBegin方法中根据点击位置判断所在行所在index,最后判断index是否在range内,若在,则响应事件。

  首先定义可点击的文本model,该model主要含有3个属性,string-用于回调显示,range-用于判断位置,attributes-用于绘制文本

class LinkAttributesModel:NSObject {    var string:String!    var range:NSRange!    var attributes:Dictionary
!}

   接着在label子类实现方法setString(string:String,attributes:Dictionary<NSAttributedStringKey,Any>?,linkArr:Array<LinkAttributesModel>),第一个参数是显示string,第二个参数是string的属性,第三个参数是一个可点击文本的集合,需要手动赋值

// 声明func setString(string:String,attributes:Dictionary
?,linkArr:Array
) { locLinkArr = linkArr; let attributedString = NSMutableAttributedString(string: string, attributes: attributes) for linkMdl in linkArr { attributedString.addAttributes(linkMdl.attributes, range: linkMdl.range) }// self.attributedText = attributedString tmpAttributedString = attributedString // create frameRef let frameSetter = CTFramesetterCreateWithAttributedString(attributedString) let path = CGMutablePath() path.addRect(self.bounds) frameRef = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, string.count), path, nil) self.isUserInteractionEnabled = true }// 调用// 构造属性model var mdlArr = [LinkAttributesModel]() for i in 0...2 { let mdl = LinkAttributesModel() let loc = i*10 let range = NSMakeRange(loc, 5) mdl.range = range let startIdx = showString.index(showString.startIndex, offsetBy: range.location) let endIdx = showString.index(startIdx, offsetBy: range.length) mdl.string = String(showString[startIdx...endIdx]) let randomColor = UIColor(red: CGFloat(arc4random_uniform(256))/255.0, green: CGFloat(arc4random_uniform(256))/255.0, blue: CGFloat(arc4random_uniform(256))/255.0, alpha: 1) mdl.attributes = [NSAttributedStringKey.foregroundColor:randomColor] mdlArr.append(mdl) } let lbl = Taplabel(frame:self.view.bounds.insetBy(dx: 0, dy: 50)) let style = NSMutableParagraphStyle() style.lineSpacing = 10 lbl.setString(string: showString, attributes: [NSAttributedStringKey.font:UIFont.systemFont(ofSize: 20),NSAttributedStringKey.paragraphStyle:style], linkArr: mdlArr)

   最后根据属性文本创建对应的frameRef,然后遍历其CTLine数组,判断点击的位置在哪行内,再根据x获取当前行的偏移位置index,最后遍历linkAttributesModel,判断range是否包含index,如果包含,则触发回调事件

func touchEvents(pt:CGPoint) {        if (frameRef == nil) {return}        let lines:[CTLine] = CTFrameGetLines(frameRef!) as! [CTLine]        let lineCount = lines.count        if (lineCount == 0) {return}//        let flipTransform = CGAffineTransform(translationX: 0, y: self.bounds.size.height).scaledBy(x: 1, y: -1)        for i in 0..
pt.x) { stringIndex = stringIndex - 1 } for linkMdl in locLinkArr! { if linkMdl.range.contains(stringIndex) { tapBlock!(linkMdl.string) } } } } }

   上述代码的主要核心在于

   a.算行高  CTLineGetTypographicBounds(line,&asent,&descent,&leading)

   b.算行内偏移  CTLineGetStringIndexForPosition(line,pt)  如果根据该index算出的偏移量大于pt.x,则index-1

   c.判断range包含  range.contains(index)

 

2.图文绘制

思路:NSAttributedString中插入占位空白符-关联图片属性。图片宽高由CTRunDelegate,图片可藏于追加属性中。ctx.draw(image,in:drawRect)时遍历CTLine,寻找含有CTRunDelegate的CTRun,如果存在,则获取图片的相应数组,构造drawRect和image绘制图片。

  追加图片属性

func appendImage(attrStr:NSAttributedString)->NSAttributedString {        var callBacks = CTRunDelegateCallbacks(version: kCTRunDelegateVersion1, dealloc: { (pointer) in        }, getAscent: { (ref) -> CGFloat in            let dic = ref.assumingMemoryBound(to: NSDictionary.self)            return dic.pointee.object(forKey: "height") as! CGFloat        }, getDescent: { (ref) -> CGFloat in            return 0        }) { (ref) -> CGFloat in            let dic = ref.assumingMemoryBound(to: NSDictionary.self)            return dic.pointee.object(forKey: "width") as! CGFloat        }                let imageData:Dictionary
= ["height":100,"width":200] let imageDataPointer = UnsafeMutablePointer
>.allocate(capacity: 1) imageDataPointer.initialize(to: imageData) let runDelegate = CTRunDelegateCreate(&callBacks, imageDataPointer) let runAttributes:[NSAttributedStringKey:Any] = [kCTRunDelegateAttributeName as NSAttributedStringKey:runDelegate as Any] let runAttributeStr = NSMutableAttributedString(string: " ", attributes: runAttributes) runAttributeStr.addAttribute(NSAttributedStringKey(rawValue: "imageName"), value: "shot", range: NSMakeRange(0, 1)) let mutableAttrStr = NSMutableAttributedString(attributedString: attrStr) let whiteSpaceStr = createAttributedString(str: "临时换行\n") let suffixStr = createAttributedString(str: "\nhaha insert image succeed") mutableAttrStr.append(whiteSpaceStr) mutableAttrStr.append(runAttributeStr) mutableAttrStr.append(suffixStr) return mutableAttrStr }

   绘制追加的图片属性

func drawImage(frame:CTFrame,ctx:CGContext) {        let lines = CTFrameGetLines(frame) as Array        var lineOrigins:Array
= Array(repeating: .zero, count: lines.count) CTFrameGetLineOrigins(frame, CFRange(location: 0, length: 0), &lineOrigins) for i in 0..

   关键代码是

  a.获取lineOrigin  CTFrameGetLineOrigins(frame, CFRange(location: 0, length: 0), &lineOrigins)

  b.获取width,height  CTRunGetTypographicBounds(run, CFRange(location: 0, length: 0), &ascent, &descent, nil)  //图片忽略leading属性

  c.获取x偏移量  lineOrigins[i].x+CTLineGetOffsetForStringIndex(line,CTRunGetStringRange(run).location,nil)

  d.获取图片  runAttributes.object(forKey:"imageName")

转载于:https://www.cnblogs.com/xiaoerheiwatu/p/10036147.html

你可能感兴趣的文章
微信小程序登录 该死的官方文档TypeError: the JSON object must be str, not 'bytes'
查看>>
VMware 虚拟机克隆 CentOS 6.5 之后,网络配置问题的解决方案
查看>>
Python ( 1 ) ----- 简介
查看>>
[linux基础学习]run level
查看>>
第七周学习总结
查看>>
一步步的教你安装UChome (UChome 安装教程)
查看>>
[DeeplearningAI笔记]序列模型1.5-1.6不同类型的循环神经网络/语言模型与序列生成...
查看>>
P2533 [AHOI2012]信号塔
查看>>
Android电话拨号器(uri格式)与四种设置点击事件的方法
查看>>
java web中对json的使用
查看>>
TYVJ P1051 选课 Label:多叉转二叉&&树形dp(虐心♥)
查看>>
将数据库中提取出来的数据在后台进行分页处理
查看>>
bzoj1034
查看>>
百度地图 鼠标绘制,获取矩形,多边形的顶点经纬度
查看>>
回文树模板
查看>>
struts2之防止表单重复提交
查看>>
【转】Netty系列之Netty并发编程分析
查看>>
cf591d
查看>>
图片存储系统TFS
查看>>
MYSQL备份与恢复
查看>>