核心文字字形位置

时间:2016-11-27 17:50:55

标签: ios uilabel core-graphics core-text

我一直在研究使用Core Text的视图,并且在使用字形位置方面遇到了一些麻烦。我想要做的是在UILabel上覆盖一些文本路径,但我发现一切都有点偏。与标签相比,我是否遗漏了与职位相关的内容?谢谢!

注意:绿色文本使用核心图形渲染,而白色是其背后的标签。

enter image description here

func renderString(from text: String, shapeLayer :(CAShapeLayer) -> Void) -> ([CGPoint], [CAShapeLayer]) {
    var letterLayers :[CAShapeLayer] = []
    var letterPositions :[CGPoint] = []

    let runFont = CTFontCreateWithName(font.fontName as CFString?, font.pointSize, nil)//unsafeBitCast(CFDictionaryGetValue(CTRunGetAttributes(run), Unmanaged.passUnretained(kCTFontAttributeName).toOpaque()), to: CTFont.self)
    var alignment = CTTextAlignment.left
    let alignmentSetting = [CTParagraphStyleSetting(spec: .alignment, valueSize: MemoryLayout.size(ofValue: alignment), value: &alignment)]
    let paragraphStyle = CTParagraphStyleCreate(alignmentSetting, alignmentSetting.count)

    let attributedString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0)
    CFAttributedStringReplaceString(attributedString, CFRangeMake(0, 0), text as CFString!)
    CFAttributedStringSetAttribute(attributedString, CFRangeMake(0, CFAttributedStringGetLength(attributedString)), kCTFontAttributeName, runFont)
    CFAttributedStringSetAttribute(attributedString, CFRangeMake(0, CFAttributedStringGetLength(attributedString)), kCTParagraphStyleAttributeName, paragraphStyle)

    let framesetter = CTFramesetterCreateWithAttributedString(attributedString!)
    let path = UIBezierPath(rect: bounds).cgPath
    let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, nil)
    let lines = CTFrameGetLines(frame)

    for index in 0..<CFArrayGetCount(lines) {
        var line = unsafeBitCast(CFArrayGetValueAtIndex(lines, index), to: CTLine.self)

        line = CTLineCreateJustifiedLine(line, 0.0, Double(bounds.width))!

        var lineOrigin :CGPoint = CGPoint()
        CTFrameGetLineOrigins(frame, CFRangeMake(index, 1), &lineOrigin)

        var ascent :CGFloat = CGFloat()
        var descent :CGFloat = CGFloat()
        var leading :CGFloat = CGFloat()

        CTLineGetTypographicBounds(line, &ascent, &descent, &leading)

        let lineHeight = ascent + descent + leading

        let runArray = CTLineGetGlyphRuns(line)

        for index in 0..<CFArrayGetCount(runArray) {
            let run = unsafeBitCast(CFArrayGetValueAtIndex(runArray, index), to: CTRun.self)

            var glyphs = [CGGlyph](repeating: CGGlyph(), count: text.characters.count)
            var positions = [CGPoint](repeating: CGPoint(), count: text.characters.count)
            let range = CFRangeMake(0, 0)
            CTRunGetGlyphs(run, range, &glyphs)
            CTRunGetPositions(run, range, &positions)

            var glyphBoundingRects = [CGRect](repeating: CGRect(), count: text.characters.count)
            CTFontGetBoundingRectsForGlyphs(runFont, .default, glyphs, &glyphBoundingRects, text.characters.count)

            for glyphIndex in 0..<glyphs.count {
                let glyph = glyphs[glyphIndex]
                let position = positions[glyphIndex]
                let glyphBounds :CGRect = glyphBoundingRects[glyphIndex]
               // let offset = CTLineGetOffsetForStringIndex(line, glyphIndex, nil)

                if let letter = CTFontCreatePathForGlyph(runFont, glyph, nil) {
                    let letterLayer = CAShapeLayer()
                    letterLayer.path = letter

                    letterLayer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
                    letterLayer.isGeometryFlipped = true
                    letterLayer.bounds = glyphBounds
                    let x = lineOrigin.x + position.x + glyphBounds.minX + glyphBounds.width / 2
                    let y = position.y + lineHeight - lineOrigin.y - letterLayer.bounds.height / 2

                    letterLayer.position = CGPoint(x: x, y: y)
                   // letterLayer.backgroundColor = UIColor.red.cgColor
                    letterLayer.fillColor = UIColor.green.cgColor

                    letterLayers.append(letterLayer)
                    letterPositions.append(position)

                    shapeLayer(letterLayer)
                } else {
                    print("Letter is nil.")
                }
            }
        }
    }

    return (letterPositions, letterLayers)
}

0 个答案:

没有答案