在我们创建想要的形状之后,我们可以将这些属性设置为 stroke color, fill color 和stroke dash pattern。
我们可以对这些属性进行动画:
• path: 渐变 layer 的形状为其它样子。
• fillColor: 将 shape 的填充色改为不同的颜色。
• lineDashPhase: 在你的形状周围创建一个 marquee 或 “marching ants” 效果
• lineWidth: 增加或缩小你的线条的线条尺寸。
现在我们实现一个小例子,例子最后效果是这样的:
代码实现
• photoLayer: avatar image layer
• circleLayer: 画圆 layer
• maskLayer: mask layer
• label: player’s name label
bounce-off animation
func searchForOpponent() {
let avatarSize = myAvatar.frame.size
let bounceXOffset: CGFloat = avatarSize.width/1.9
let morphSize = CGSize(
width: avatarSize.width * 0.85,
height: avatarSize.height * 1.1)
let rightBouncePoint = CGPoint(
x: view.frame.size.width/2.0 + bounceXOffset,
y: myAvatar.center.y)
let leftBouncePoint = CGPoint(
x: view.frame.size.width/2.0 - bounceXOffset,
y: myAvatar.center.y)
myAvatar.bounceOff(point: rightBouncePoint, morphSize: morphSize)
opponentAvatar.bounceOff(point: leftBouncePoint, morphSize: morphSize)
delay(seconds: 4.0, completion: foundOpponent)
}
func foundOpponent() {
status.text = "Connecting..."
opponentAvatar.image = UIImage(named: "avatar-2")
opponentAvatar.name = "Ray"
delay(seconds: 4.0, completion: connectedToOpponent)
}
func connectedToOpponent() {
myAvatar.shouldTransitionToFinishedState = true
opponentAvatar.shouldTransitionToFinishedState = true
delay(seconds: 1.0, completion: completed)
}
func completed() {
status.text = "Ready to play"
UIView.animate(withDuration: 0.2) {
self.vs.alpha = 1.0
self.searchAgain.alpha = 1.0
}
}
Morphing shapes 形状渐变
当两个 avatars 相撞时,它们应该在这个完全弹性碰撞中稍微挤压一下。视图控制器将通过一个 morph size,使头像形状变得稍高和稍窄的效果,如图所示:
这样,当他们在屏幕中间相遇时,看起来头像互相挤压。
核心代码:
func bounceOff(point: CGPoint, morphSize: CGSize) {
let originalCenter = center
UIView.animate(withDuration: animationDuration, delay: 0.0,
usingSpringWithDamping: 0.8, initialSpringVelocity: 0.0,
animations: {
self.center = point
}, completion: { _ in
//complete bounce to
if self.shouldTransitionToFinishedState {
self.animateToSquare()
}
})
UIView.animate(withDuration: animationDuration,
delay: animationDuration,
usingSpringWithDamping: 0.7,
initialSpringVelocity: 1.0,
animations: {
self.center = originalCenter
}, completion: { _ in
delay(seconds: 0.1) {
if !self.isSquare {
self.bounceOff(point: point, morphSize: morphSize)
}
}
})
let morphedFrame = (originalCenter.x > point.x) ?
CGRect(x: 0.0, y: bounds.height - morphSize.height,
width: morphSize.width, height: morphSize.height):
CGRect(x: bounds.width - morphSize.width,
y: bounds.height - morphSize.height,
width: morphSize.width, height: morphSize.height)
let morphAnimation = CABasicAnimation(keyPath: "path")
morphAnimation.duration = animationDuration
morphAnimation.toValue = UIBezierPath(ovalIn: morphedFrame).cgPath
morphAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
circleLayer.add(morphAnimation, forKey: nil)
maskLayer.add(morphAnimation, forKey: nil)
}