非系统字体的CTFrameGetLineOrigins错误

时间:2018-07-13 08:26:10

标签: ios swift uikit uitextview core-text

use bold system font use ChalkboardSE-Bold font

public func calculateTextMetrics(for attrString: NSAttributedString, maxWidth: CGFloat) -> (suggestSize: CGSize, charFrames: [CGRect]) {
var rects = [CGRect]()

let frameSetter = CTFramesetterCreateWithAttributedString(attrString)
let stringRange = CFRangeMake(0, attrString.string.count)
let maxSize = CGSize.init(width: maxWidth, height: .infinity)
let suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(frameSetter, stringRange, nil, maxSize, nil)
let textPath = CGPath(rect: CGRect(origin: .zero, size: suggestedSize), transform: nil)
let textFrame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), textPath, nil)

let lines: CFArray = CTFrameGetLines(textFrame)
let linesCount = CFArrayGetCount(lines)
var lineOrigins = [CGPoint](repeating: .zero, count: linesCount)
var lineFrames = [CGRect](repeating: .zero, count: linesCount)
CTFrameGetLineOrigins(textFrame, CFRangeMake(0, 0), &lineOrigins)

for lineIndex in 0 ..< linesCount {
    let linePointer = CFArrayGetValueAtIndex(lines, lineIndex)
    let line = unsafeBitCast(linePointer, to: CTLine.self)
    let lineOrigin = lineOrigins[lineIndex]

    var ascent: CGFloat = 0, descent: CGFloat = 0, leading: CGFloat = 0
    let lineWidth = CTLineGetTypographicBounds(line, &ascent, &descent, &leading) // if not valid line width will be zero
    let lineHeight = ascent + descent + leading
    lineFrames[lineIndex].origin = CGPoint(x: lineOrigin.x, y: lineOrigin.y) // lineOrigin is at baseline
    lineFrames[lineIndex].size = CGSize(width: CGFloat(lineWidth), height: CGFloat(lineHeight))

    let runs = CTLineGetGlyphRuns(line)
    let runsCount = CFArrayGetCount(runs)

    for runIndex in 0 ..< runsCount {
        let runPointer = CFArrayGetValueAtIndex(runs, runIndex)
        let run = unsafeBitCast(runPointer, to: CTRun.self)
        let runAttributes = CTRunGetAttributes(run)

        let fontKey = Unmanaged.passRetained(kCTFontAttributeName).toOpaque()
        let fontPointer = CFDictionaryGetValue(runAttributes, fontKey)
        let font = unsafeBitCast(fontPointer, to: CTFont.self)

        let runRange = CTRunGetStringRange(run)
        let runStart = runRange.location
        let runEnd = runRange.location + runRange.length

        for stringIndex in runStart ..< runEnd {
            let glyphIndex = stringIndex - runStart
            let glyphRange = CFRangeMake(glyphIndex, 1)
            var glyph = CGGlyph()
            CTRunGetGlyphs(run, glyphRange, &glyph)

            var glyphBound: CGRect = .zero
            CTFontGetBoundingRectsForGlyphs(font, .default, &glyph, &glyphBound, 1)
            if glyphBound.size == .zero {
                let systemFont = UIFont.systemFont(ofSize: CTFontGetSize(font)) as CTFont
                CTFontGetBoundingRectsForGlyphs(systemFont, .default, &glyph, &glyphBound, 1)
            }

            let glyphOffset = CTLineGetOffsetForStringIndex(line, stringIndex, nil)
            glyphBound.origin.x += glyphOffset
            glyphBound.origin.y += lineOrigin.y

            rects.append(glyphBound)
        }
    }
}
return (suggestedSize, rects)

}

您好: 我已经使用该代码来计算字符范围,对于系统字体,似乎得到了几乎正确的结果,但是对于另一种字体“ ChalkboardSE-Bold”(fontSize = 20),该范围似乎比实际文本范围要小一些(文本由UITextView呈现,并且我已将文本布局边距,文本容器插入,lineFragemntPadding设置为零)。谁能找到原因?

0 个答案:

没有答案