使用 CGPaths 和 CAShapeLayers 动画绘制字母
Animating the drawing of letters with CGPaths and CAShapeLayers
我目前正在使用此代码为角色绘制动画:
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!)
}
从一个字符创建一个 bezierpath(在本例中为 "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
时,附加路径会如您所料直接添加到原始路径上。如果我想画一个所有字符都有适当间距等的字母,我该怎么办?
谢谢你的时间。
您可以在路径上使用翻译(使用 CGAffineTransformMakeTranslation
)来执行此操作,因为路径没有 "position",它只是一组点。但是要在字符的每次迭代中进行翻译,我们需要路径的当前宽度 - 我们可以为此使用 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
}
我目前正在使用此代码为角色绘制动画:
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!)
}
从一个字符创建一个 bezierpath(在本例中为 "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
时,附加路径会如您所料直接添加到原始路径上。如果我想画一个所有字符都有适当间距等的字母,我该怎么办?
谢谢你的时间。
您可以在路径上使用翻译(使用 CGAffineTransformMakeTranslation
)来执行此操作,因为路径没有 "position",它只是一组点。但是要在字符的每次迭代中进行翻译,我们需要路径的当前宽度 - 我们可以为此使用 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
}