使用 CGPaths 和 CAShapeLayers 动画绘制字母

Posted

技术标签:

【中文标题】使用 CGPaths 和 CAShapeLayers 动画绘制字母【英文标题】:Animating the drawing of letters with CGPaths and CAShapeLayers 【发布时间】:2015-12-25 18:08:57 【问题描述】:

我目前正在使用此代码来动画角色的绘制:

var path = UIBezierPath()


    var unichars = [UniChar]("J".utf16)
    var glyphs = [CGGlyph](count: unichars.count, repeatedValue: 0)

    let gotGlyphs = CTFontGetGlyphsForCharacters(font, &unichars, &glyphs, unichars.count)
    if gotGlyphs 
        let cgpath = CTFontCreatePathForGlyph(font, glyphs[0], nil)
         path = UIBezierPath(CGPath: cgpath!)

    

从一个字符(在本例中为“J”)创建一个贝塞尔路径。 Get path to trace out a character in an ios UIFont

然后我创建一个CAShapeLayer() 并为其添加动画。

 let layer = CAShapeLayer()
   layer.position = //CGPoint
    layer.bounds = //CGRect()
    view.layer.addSublayer(layer)

    layer.path = path.CGPath

    layer.lineWidth = 5.0
    layer.strokeColor = UIColor.blackColor().CGColor
    layer.fillColor = UIColor.clearColor().CGColor
    layer.geometryFlipped = true

    layer.strokeStart = 0.0
    layer.strokeEnd = 1.0

    let anim = CABasicAnimation(keyPath: "strokeEnd")
    anim.duration = 8.0
    anim.fromValue = 0.0
    anim.toValue = 1.0

    layer.addAnimation(anim, forKey: nil)

结果是我选择的角色动画正确。但是,当我使用.appendPath()path 添加另一个路径时,附加的路径会如您所料那样直接添加到原始路径中。如果我想绘制一个所有字符都有适当间距等的字母,我该怎么办? 感谢您的宝贵时间。

【问题讨论】:

【参考方案1】:

您可以在路径上使用平移(使用CGAffineTransformMakeTranslation)来做到这一点,因为路径没有“位置”,它只是一组点。但是要对字符的每次迭代进行翻译,我们需要路径的当前宽度——我们可以为此使用CGPathGetBoundingBox(),它获取路径将覆盖的框。所以有了我们需要的一切,我们可以做一个例子。为整个单词制作一条路径将是这样的:

let word = "Test"
let path = UIBezierPath()
let spacing: CGFloat = 50
var i: CGFloat = 0
for letter in word.characters 
    let newPath = getPathForLetter(letter)
    let actualPathRect = CGPathGetBoundingBox(path.CGPath)
    let transform = CGAffineTransformMakeTranslation((CGRectGetWidth(actualPathRect) + min(i, 1)*spacing), 0)
    newPath.applyTransform(transform)
    path.appendPath(newPath)
    i++

函数getPathForLetter() 只是:

func getPathForLetter(letter: Character) -> UIBezierPath 
    var path = UIBezierPath()
    let font = CTFontCreateWithName("HelveticaNeue", 64, nil)
    var unichars = [UniChar]("\(letter)".utf16)
    var glyphs = [CGGlyph](count: unichars.count, repeatedValue: 0)

    let gotGlyphs = CTFontGetGlyphsForCharacters(font, &unichars, &glyphs, unichars.count)
    if gotGlyphs 
        let cgpath = CTFontCreatePathForGlyph(font, glyphs[0], nil)
        path = UIBezierPath(CGPath: cgpath!)
    

    return path

【讨论】:

以上是关于使用 CGPaths 和 CAShapeLayers 动画绘制字母的主要内容,如果未能解决你的问题,请参考以下文章

使用 CALayer 显示 CGPaths 会影响 iOS 中的性能吗?

两条 CGpaths - 1 CAAnimation - 但应该重复第二条路径

使用UIBezierPath和CAShapeLayer画各种图形

[[CAShapeLayer alloc] init] 和 [CAShapeLayer layer] 的区别

关于CAShapeLayer

CAShapeLayer和贝塞尔曲线配合使用