如何使用 CoreGrahpics 和 Core 动画绘制文本

How to draw a text using CoreGrahpics & Core animation

我想实现这种animation.please检查这个URL

https://www.dropbox.com/s/gz9vfy5refsh7a5/Screen.mov?dl=0

我正在添加我在项目中使用的代码,在该项目中我使用 Core Graphics 来渲染带动画的文本,但我无法为上述 link[= 中显示的文本设置动画12=]

这是我用来在屏幕上呈现文本的代码

    let context = UIGraphicsGetCurrentContext()!
    context.saveGState()
    context.setAlpha(noLightText)

    let nOLIGHTRect = CGRect(x: 145.66, y: 590, width: 449.38, height: 125)
    let nOLIGHTStyle = NSMutableParagraphStyle()
    nOLIGHTStyle.alignment = .center
    let nOLIGHTFontAttributes = [
        .font: UIFont(name: "Futura-CondensedExtraBold", size: 96)!,
        .foregroundColor: nOLIGHTColor,
        .paragraphStyle: nOLIGHTStyle,
        ] as [NSAttributedStringKey: Any]

    "NO LIGHT".draw(in: nOLIGHTRect, withAttributes: nOLIGHTFontAttributes)

    context.restoreGState()


    //// LOW LIGHT Drawing
    context.saveGState()
    context.setAlpha(_0)

    let lOWLIGHTRect = CGRect(x: 145.94, y: 590, width: 449.38, height: 125)
    let lOWLIGHTStyle = NSMutableParagraphStyle()
    lOWLIGHTStyle.alignment = .left
    let lOWLIGHTFontAttributes = [
        .font: UIFont(name: "Futura-CondensedExtraBold", size: 96)!,
        .foregroundColor: lOWLIGHTColor,
        .paragraphStyle: lOWLIGHTStyle,
        ] as [NSAttributedStringKey: Any]

    "LOW LIGHT".draw(in: lOWLIGHTRect, withAttributes: lOWLIGHTFontAttributes)

    context.restoreGState()


    //// MID LIGHT Drawing
    context.saveGState()
    context.setAlpha(mediumLightText)

    let mIDLIGHTRect = CGRect(x: 145.77, y: 590, width: 449.38, height: 125)
    let mIDLIGHTStyle = NSMutableParagraphStyle()
    mIDLIGHTStyle.alignment = .left
    let mIDLIGHTFontAttributes = [
        .font: UIFont(name: "Futura-CondensedExtraBold", size: 96)!,
        .foregroundColor: mIDLIGHTColor,
        .paragraphStyle: mIDLIGHTStyle,
        ] as [NSAttributedStringKey: Any]


    "MID LIGHT".draw(in: mIDLIGHTRect, withAttributes: mIDLIGHTFontAttributes)

    context.restoreGState()

如果您想同时为多个字符的轮廓笔画设置动画,您可以:

  • 确定每个角色的 CGPaths
  • 将 CGPaths 映射到 CAShapeLayers
  • 动画 strokeEnd 属性

这看起来像这样:

请注意: iOS 使用的字体是使用 TrueType 或 OpenType 格式的轮廓字体。这意味着每个字形都使用直线和曲线来定义其边界。我们通常在渲染字形时看到的是填充区域。因此,如果 'strokeEnd' 属性 是动画的,则绘制字形的轮廓。以下代码显示了如何实现这一点。

以人类编写文本的方式对文本进行动画处理会更加费力(例如,使用笔划字体而不是轮廓字体加上关联的引擎或使用 user-defined 矢量路径表示每个字符)

var charLayers = [CAShapeLayer]()

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    for layer in self.charLayers {
        layer.removeFromSuperlayer()
    }

    let stringAttributes = [ NSAttributedStringKey.font: UIFont(name: "Futura-CondensedExtraBold", size: 64.0)! ]
    let attributedString = NSMutableAttributedString(string: "hello world", attributes: stringAttributes )
    let charPaths = self.characterPaths(attributedString: attributedString, position: CGPoint(x: 24, y: 192))

    self.charLayers = charPaths.map { path -> CAShapeLayer in
        let shapeLayer = CAShapeLayer()
        shapeLayer.fillColor = UIColor.clear.cgColor
        shapeLayer.strokeColor = UIColor.red.cgColor
        shapeLayer.lineWidth = 2
        shapeLayer.path = path
        return shapeLayer
    }

    for layer in self.charLayers {
        view.layer.addSublayer(layer)
        let animation = CABasicAnimation(keyPath: "strokeEnd")
        animation.fromValue = 0
        animation.duration = 2.2
        layer.add(animation, forKey: "charAnimation")
    }
}

func characterPaths(attributedString: NSAttributedString, position: CGPoint) -> [CGPath] {

    let line = CTLineCreateWithAttributedString(attributedString)

    guard let glyphRuns = CTLineGetGlyphRuns(line) as? [CTRun] else { return []}

    var characterPaths = [CGPath]()

    for glyphRun in glyphRuns {
        guard let attributes = CTRunGetAttributes(glyphRun) as? [String:AnyObject] else { continue }
        let font = attributes[kCTFontAttributeName as String] as! CTFont

        for index in 0..<CTRunGetGlyphCount(glyphRun) {
            let glyphRange = CFRangeMake(index, 1)

            var glyph = CGGlyph()
            CTRunGetGlyphs(glyphRun, glyphRange, &glyph)

            var characterPosition = CGPoint()
            CTRunGetPositions(glyphRun, glyphRange, &characterPosition)
            characterPosition.x += position.x
            characterPosition.y += position.y

            if let glyphPath = CTFontCreatePathForGlyph(font, glyph, nil) {
                var transform = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: characterPosition.x, ty: characterPosition.y)
                if let charPath = glyphPath.copy(using: &transform) {
                    characterPaths.append(charPath)
                }
            }
        }
    }
    return characterPaths
}