ChatBubble动画
前言
最近看了一个动画的实现,觉得比较有意思,就自己重新实现了一下。效果图如下。
chatBubbleAnimation.gif动画看起来比较简单,就是3个点在做position,scale,opacity的组合动画。
主要是3个点的实现。最直接的,可以用3个view来写。然后自己控制动画间隔。看了作者的实现,觉得这个思路比较好,就是用CAReplicatorLayer。它对图层进行copy,并且可设置个数,图层之间的变换,动画延迟时间等等。
然后用到了@IBDesignable,可以在xib中直接看效果。@IBInspectable,在inspector中设置属性值。
Paste_Image.pngCAReplicatorLayer
The CAReplicatorLayer class creates a specified number of copies of its sublayers (the source layer), each copy potentially having geometric, temporal and color transformations applied to it.
CAReplicatorLayer 从源图层中copy出多个图层,并且可以对这些图层进行一系列的颜色,位置的变换。
...
// 设置图层个数
replicatorLayer.instanceCount = 3
// 设置图层变换,这里是每个图层直接的x间隔
replicatorLayer.instanceTransform = CATransform3DMakeTranslation(dotSize() * 1.6, 0, 0)
// 动画间隔时间
replicatorLayer.instanceDelay = 0.1
dotLayer = CALayer()
dotLayer.bounds = CGRectMake(0, 0, dotSize(), dotSize())
dotLayer.position = CGPointMake(center.x - dotSize() * 1.6, center.y + dotSize() * 0.2)
dotLayer.cornerRadius = dotSize() / 2
dotLayer.backgroundColor = dotColor.CGColor
replicatorLayer.addSublayer(dotLayer)
CAReplicatorLayer还有一些其他的属性。颜色值,透明度的设置等。
public var instanceColor: CGColor?
/* The color components added to the color of instance k-1 to produce
* the modulation color of instance k. Defaults to the clear color (no
* change). Animatable. */
public var instanceRedOffset: Float
public var instanceGreenOffset: Float
public var instanceBlueOffset: Float
public var instanceAlphaOffset: Float
进一步学习可参考:
http://www.ios-animations-by-emails.com/posts/2015-march#tutorial
https://zsisme.gitbooks.io/ios-/content/chapter6/careplicatorLayer.html
http://tuohuang.info/14.html#.VysQ0ZN95Gw
动画实现
气泡最外层的路径,是个贝塞尔曲线,用PaintCode生成,拖一下形状,就会自动转换成代码,比较方便。
上面说过,跳动的3个点的动画是组合动画,了解过组合动画的应该觉得它比较简单了。position.y, scale, opacity的组合。
这里我将动画的生成单独抽出到AnimationHelper,各司其职,减少耦合。
let move = AnimationHelper.createAnimation(.yPosition, fromValue: dotLayer.position.y, toValue: dotLayer.position.y - dotSize(), duration: 0.5)
let alpha = AnimationHelper.createAnimation(.opacity, fromValue: 1, toValue: 0, duration: 0.5)
let scale = AnimationHelper.createAnimation(.scale, fromValue: 1, toValue: 1.3, duration: 0.5)
let animationGroup = AnimationHelper.animationGroup(0.5, name: "up", animations: [move, alpha, scale])
animationGroup.delegate = self
dotLayer.addAnimation(animationGroup, forKey: "dotAniamtion")
在向上跳动的动画结束之后,会进行一个向下的动画,动画类似,只是值反过来了。如此往复。
override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
if let value = anim.valueForKey("animation") as? String {
if value == "up" {
animationEnd()
} else if value == "down" {
animationStart()
}
}
}