1.CoreText的图片点击
* 根据绘制图片时获取到图片的frame
* 判断是否点击了图片
// 坐标转换
let location = CGPoint(x: point.x, y: self.bounds.size.height - point.y)
if imageFrame.contains(location) {
print("点击了图片")
return
}
2.CoreText的文字点击
- 遍历CTLine,获取每一个CTLine的frame,判断点击了哪一行
- 获取CTLine对应的range,根据range获取到点击对应的CTRun
- CTRunGetTypographicBounds获取descent,ascent等
- 转换坐标,判断是否在点击范围中
guard let frame = ctFrame else { return }
let lines = CTFrameGetLines(frame) as Array
var origins = [CGPoint](repeating: CGPoint.zero, count: lines.count)
CTFrameGetLineOrigins(frame, CFRange(location: 0, length: 0), &origins)
var ranges = [CFRange](repeating: CFRange(location: 0, length: 0), count: lines.count)
var lineAscent: CGFloat = 0
var lineDescent: CGFloat = 0
for i in 0..<lines.count {
let line = lines[i] as! CTLine
let range = CTLineGetStringRange(line)
ranges[i] = range
// 点击的某一行的Frame[翻转坐标后的frame]
CTLineGetTypographicBounds(line, &lineAscent, &lineDescent, nil)
let lineFrame = CGRect(x: origins[i].x, y: self.bounds.size.height - origins[i].y - (lineAscent + lineDescent), width: CTLineGetOffsetForStringIndex(line, 100000, nil), height: lineAscent + lineDescent)
if lineFrame.contains(point) {
for j in range.location..<(range.location + range.length) {
let runFrame = frameForCTRunWithIndex(index: j, line: line, origin: origins[i])
let finalFrame = CGRect(x: runFrame.origin.x, y: self.bounds.height - runFrame.origin.y - runFrame.height, width: runFrame.width, height: runFrame.height)
if finalFrame.contains(point) {
print("点击了\(i)行, 第\(j - range.location)个元素")
break
}
}
break
}
}
func frameForCTRunWithIndex(index: Int, line: CTLine, origin: CGPoint) -> CGRect {
var offsetX = CTLineGetOffsetForStringIndex(line, index, nil)
var offsetX2 = CTLineGetOffsetForStringIndex(line, index + 1, nil)
offsetX += origin.x
offsetX2 += origin.x
let offsetY = origin.y
var lineAscent: CGFloat = 0
var lineDescent: CGFloat = 0
var runs = CTLineGetGlyphRuns(line) as Array
var currentRun: CTRun?
for k in 0..<runs.count {
let run = runs[k] as! CTRun
let range = NSRange(location: CTRunGetStringRange(run).location, length: CTRunGetStringRange(run).length)
if index <= (range.location + range.length - 1) && (index >= range.location) {
currentRun = run
break
}
}
if let currentRun = currentRun {
CTRunGetTypographicBounds(currentRun, CFRange(location: 0, length: 0), &lineAscent, &lineDescent, nil)
let height = lineDescent + lineAscent
return CGRect(x: offsetX, y: offsetY, width: offsetX2 - offsetX, height: height)
}
return CGRect.zero
}