iOS核心动画高级技巧(笔记)——(七)显式动画

属性动画

  • CABasicAnimation

找到一篇很详细的CABasicAnimation使用总结

  • CAKeyframeAnimation

CAKeyframeAnimation用values数组代替fromValuetoValue,里面的元素称为”关键帧“,动画对象会在指定的时间内,依次显示values数组中的每一个关键帧。
path属性:可以设置一个CGPathRef、CGMutabelPathRef,让图层按照路径轨迹移动,path只对CALayeranchorPointposition起作用,如果设置了path,那么values将被忽略。
keyTimes:可以为对应的关键帧指定对一个你的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每一帧。如果没有设置keyTimes,各个关键帧的时间是平分的。
rotationMode属性,设置它为常量kCAAnimationRotateAuto,图层将会根据曲线的切线自动旋转。

动画组

  • CABasicAnimationCAKeyframeAnimation仅仅作用于单独的属性,而CAAnimationGroup可以把这些动画组合在一起。CAAnimationGroup是另一个继承于CAAnimation的子类,它添加了一个animations数组的属性,用来组合别的动画。
    let groupAnimation = CAAnimationGroup()
    groupAnimation.animations = [animation1,animation2]
    groupAnimation.duration = 4.0
    self.shipLayer.addAnimation(groupAnimation, forKey: nil)

过渡

  • 有时候对于iOS应用程序来说,希望能通过属性动画来对比较难做动画的布局进行一些改变。比如交换一段文本和图片,或者用一段网格视图来替换,等等。属性动画只对图层的可动画属性起作用,所以如果要改变一个不能动画的属性(比如图片),或者从层级关系中添加或者移除图层,属性动画将不起作用。
    于是就有了过渡的概念。过渡并不像属性动画那样平滑地在两个值之间做动画,而是影响到整个图层的变化。过渡动画首先展示之前的图层外观,然后通过一个交换过渡到新的外观。
    为了创建一个过渡动画,我们将使用CATransition,同样是另一个CAAnimation的子类,和别的子类不同,CATransition有一个typesubtype来标识变换效果。
  • type属性是一个String类型,可以被设置成如下类型:
    kCATransitionFade
    kCATransitionMoveIn
    kCATransitionPush
    kCATransitionReveal
    除了这四种类型,可以通过一些别的方法来自定义过渡效果。默认的过渡类型是kCATransitionFade,当你在改变图层属性之后,就创建了一个平滑的淡入淡出效果。
    kCATransitionPush创建了一个新的图层,从边缘的一侧滑动进来,把旧图层从另一侧推出去的效果。
    kCATransitionMoveIn从顶部滑动进入,但不像推送动画那样把老图层推走。
    kCATransitionReveal把原始的图层滑动出去来显示新的外观,而不是把新的图层滑动进入。
  • 后面三种过渡类型都有一个默认的动画方向,它们都从左侧滑入,但是你可以通过subtype来控制它们的方向,提供了如下四种类型:
    kCATransitionFromRight
    kCATransitionFromLeft
    kCATransitionFromTop
    kCATransitionFromBottom
  • 过渡动画和之前的属性动画或者动画组添加到图层上的方式一致,都是通过-addAnimation:forKey:方法。但是和属性动画不同的是,对指定的图层一次只能使用一次CATransition。
  • 隐式过渡

在自己创建的图层中对图层contents图片做的改动都会自动附上淡入淡出的动画,但是对于视图关联的图层,或者是其他隐式动画的行为,这个特性依然是被禁用的。

  • 对图层树的动画

CATransition并不作用于指定的图层属性,可以在即使不能准确得知改变了什么的情况下对图层做动画,例如,在不知道UITableView哪一行被添加或者删除的情况下,直接就可以平滑地刷新它,或者在不知道UIViewController内部的视图层级的情况下对两个不同的实例做过渡动画。
为了确保CATransition添加到的图层在过渡动画发生时不会在树状结构中被移除,一般来说,只需要将动画添加到被影响图层的superlayer

  • 自定义动画

苹果通过UIView+transitionFromView:toView:duration:options:completion:+transitionWithView:duration:options:animations:方法提供了Core Animation的过渡特性。但是这里的可用的过渡选项和CATransitiontype属性提供的常量完全不同。UIView过渡方法中options参数可以由如下常量指定:
UIViewAnimationOptionTransitionFlipFromLeft
UIViewAnimationOptionTransitionFlipFromRight
UIViewAnimationOptionTransitionCurlUp
UIViewAnimationOptionTransitionCurlDown
UIViewAnimationOptionTransitionCrossDissolve
UIViewAnimationOptionTransitionFlipFromTop
UIViewAnimationOptionTransitionFlipFromBottom
CALayer有一个-renderInContext:方法,可以通过把它绘制到Core Graphics的上下文中捕获当前内容的图片,然后在另外的视图中显示出来。如果我们把这个截屏视图置于原始视图之上,就可以遮住真实视图的所有变化,于是重新创建了一个简单的过渡效果。
renderInContext:创建自定义过渡效果
@IBAction func start(sender: UIButton) {
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, true, 0.0)
self.view.layer.renderInContext(UIGraphicsGetCurrentContext()!)
let coverImage = UIGraphicsGetImageFromCurrentImageContext()
//insert snapshot view in front of this one
let coverView = UIImageView(image: coverImage)
coverView.frame = self.view.bounds
self.view.addSubview(coverView)
//update the view (we'll simply randomize the layer background color)
let red = CGFloat(arc4random()) / CGFloat(INT_MAX)
let green = CGFloat(arc4random()) / CGFloat(INT_MAX)
let blue = CGFloat(arc4random()) / CGFloat(INT_MAX)
self.view.backgroundColor = UIColor(red: red, green: green, blue: blue, alpha: 1.0)
//perform animation (anything you like)”
UIView.animateWithDuration(1.0, animations: ({
var transform = CGAffineTransformIdentity
transform = CGAffineTransformMakeScale(0.01, 0.01)
transform = CGAffineTransformRotate(transform,CGFloat(M_PI_2))
coverView.transform = transform
coverView.alpha = 0.0
}), completion: { (finished:Bool) -> Void in coverView.removeFromSuperview()}
)
}

使用renderInContext:创建自定义过渡效果

这里有个警告:-renderInContext:捕获了图层的图片和子图层,但是不能对子图层正确地处理变换效果,而且对视频和OpenGL内容也不起作用。但是用CATransition,或者用私有的截屏方式就没有这个限制了。

在动画过程中取消动画

  • 可以用-addAnimation:forKey:方法中的key参数来在添加动画之后检索一个动画,使用如下方法:- (CAAnimation *)animationForKey:(NSString *)key;但并不支持在动画运行过程中修改动画,所以这个方法主要用来检测动画的属性,或者判断它是否被添加到当前图层中。为了终止一个指定的动画,你可以用如下方法把它从图层移除掉:- (void)removeAnimationForKey:(NSString *)key,或者移除所有动画:- (void)removeAllAnimations
    动画一旦被移除,图层的外观就立刻更新到当前的模型图层的值。一般说来,动画在结束之后被自动移除,除非设置removedOnCompletionNO,如果你设置动画在结束之后不被自动移除,那么当它不需要的时候你要手动移除它;否则它会一直存在于内存中,直到图层被销毁。
    -animationDidStop:finished:方法中的flag参数表明了动画是自然结束还是被打断,如果被打断,它会打印NO,如果允许它完成,它会打印YES

推荐阅读更多精彩内容