iOS动画指南 - 2.Layer Animations的基本使用

上篇View Animations可以实现一些简单的动效,但并不能够完全满足开发使用,自定义程度比较低,为此我们来学习下Layer Animations.
那么Layer有哪些可以自定义动画的属性呢?

  • 位置和尺寸: bounds position transform
  • 边框: borderColor borderWidth cornerRadius
  • 阴影: shadowOffset shadowOpacity shadowPath shadowRadius
  • 内容: contents mask opacity

等等,以上仅仅只是一部分.

1.开篇

还是先从位移说起吧!还记得在上一篇View Animations中是怎么实现的吗?
现在我们可以这样做:

        let flyRight = CABasicAnimation(keyPath: "position.x")
        // 开始时的位置
        flyRight.fromValue = 80
        // 结束时的位置
        flyRight.toValue = 230

        flyRight.duration = 0.5
        // 延迟0.3执行
        flyRight.beginTime = CACurrentMediaTime() + 0.3
        // 添加到dogImageView上
        dogImageView.layer.addAnimation(flyRight, forKey: nil)

这边会碰到一个问题,当动画结束后dogImageView会立即返回初始的状态,那么如果要dogImageView保持在结束状态该怎样做呢?

        let flyRight = CABasicAnimation(keyPath: "position.x")
        // 保证fillMode起作用
        flyRight.removedOnCompletion = false
        // 动画结束后,layer会保持结束状态
        flyRight.fillMode = kCAFillModeForwards
        flyRight.fromValue = 60
        flyRight.toValue = 230
        flyRight.duration = 0.5
        // 延迟执行
        flyRight.beginTime = CACurrentMediaTime() + 1

        dogImageView.layer.addAnimation(flyRight, forKey: nil)

设置fillMode的属性就行了.

fillMode的几个值的分别代表的含义:

  • kCAFillModeRemoved : 默认样式 动画结束后会回到layer的开始的状态
  • kCAFillModeForwards : 动画结束后,layer会保持结束状态
  • kCAFillModeBackwards : layer跳到fromValue的值处,然后从fromValue到toValue播放动画,最后回到layer的开始的状态
  • kCAFillModeBoth : kCAFillModeForwards和kCAFillModeBackwards的结合,即动画结束后layer保持在结束状态

fillMode = kCAFillModeBoth 演示效果:

        dogImageView.layer.position.x = 80

        let flyRight = CABasicAnimation(keyPath: "position.x")
        // 保证fillMode起作用
        flyRight.removedOnCompletion = false
        flyRight.fillMode = kCAFillModeBoth
        flyRight.fromValue = 100
        flyRight.toValue = 230
        flyRight.duration = 0.5
        flyRight.beginTime = CACurrentMediaTime() + 1
        dogImageView.layer.addAnimation(flyRight, forKey: nil)

dogImageView的初始位置为80,然后跳到100,从100开始执行动画,停在最终位置.
左面是控制台,我们给dogImageView添加了一个点击监听,发现dogImageView的位置表面上看起来是改变了,其实它还在原来的位置,也就是说layer动画并不是真实的,如果要变成真实的需要改变其position,那问题来了这个效果的使用场景是什么?
答:视图不需要交互,且动画的开始和结束需要设置特殊的值.

2.代理

如果我想在动画开始和结束的时候分别搞点事情该怎样做呢?对的,可以用代理呀!
设置下代理就能实现代理方法了.


   flyRight.delegate = self

extension ViewController { 
    override func animationDidStart(anim: CAAnimation) {
        print("动画开始调用")      
    }
    override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
        print("动画结束调用")
    }
}

使用Layer Animations可以设置好一个Animation,然后添加到不同的view上面,但这时如果我们设置了flyRight的代理,并将flyRight添加到了很多的view上面,那该怎样才能在代理方法中区分哪个是哪个呢?
用KVC设置一个name然后在代理中做一下判断就行了.

        // 设置名称
        flyRight.setValue("form", forKey: "name")
        // 方便代理中可以拿到layer
        flyRight.setValue(dogImageView.layer, forKey: "layer")

在动画结束时做一个特效

extension ViewController {
    
    override func animationDidStart(anim: CAAnimation) {
        print("动画开始调用")
        
    }
    override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
        print("动画结束调用")
        
        if let name = anim.valueForKey("name") as? String {
            if name == "form" 
                print("name is form")
                
                // 动画结束后设置一个先放大然后缩小的效果
                let layer = anim.valueForKey("layer") as? CALayer
                anim.setValue(nil, forKey: "layer")
                
                let pulse = CABasicAnimation(keyPath: "transform.scale")
                pulse.fromValue = 1.25
                pulse.toValue = 1.0
                pulse.duration = 3.25
                layer?.addAnimation(pulse, forKey: nil)         
            }
        }
    }
}

3.在动画的执行过程中移除动画

在设计交互中,常常会碰到这样的一个问题,在动画的执行过程中,由于用户的点击操作,需要提前终止动画,该怎么实现呢?很简单

        // forKey以前基本是设置为nil的,现在派上用场了.因为dogImageView上可能添加了很多动画,forKey就是为了区别哪一个
        dogImageView.layer.addAnimation(flyRight, forKey: "position")
        // 添加到需要终止的地方,就可以随时终止动画了
        dogImageView.layer.removeAnimationForKey("position")
        // 移除dogImageView上所有动画
        dogImageView.layer.removeAllAnimations()

4.动画组

还记得View Animations中的动画组吗?在Layer Animations依然有这个,只不过这次添加进去的动画是同时执行的.

        let groupAnimation = CAAnimationGroup()
        // 延迟1秒
        groupAnimation.beginTime = CACurrentMediaTime() + 1
        // 整个动画持续3秒
        groupAnimation.duration = 3
        
        groupAnimation.removedOnCompletion = false
        groupAnimation.fillMode = kCAFillModeBoth
        
        // 缓慢加速缓慢减速
        groupAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        // 重复次数
        groupAnimation.repeatCount = 4.5
        // 来回往返执行
        groupAnimation.autoreverses = true
        // 速度
        groupAnimation.speed = 2.0
        
        let scaleDown = CABasicAnimation(keyPath: "transform.scale")
        scaleDown.fromValue = 1.5
        scaleDown.toValue = 1.0
        
        let roate = CABasicAnimation(keyPath: "transform.rotation")
        roate.fromValue = CGFloat(M_PI_4)

        roate.toValue = 0.0
        
        let fade = CABasicAnimation(keyPath: "opacity")
        fade.fromValue = 0.5
        fade.toValue = 1.0
        
        groupAnimation.animations = [scaleDown, roate, fade]
        dogImageView.layer.addAnimation(groupAnimation, forKey: nil)

5.Layer的弹簧效果

还记得前面View Animations中的弹簧效果吗?底层实际上就是通过下面要介绍的CASpringAnimation来实现.
CASpringAnimation是CABasicAnimation的子类,用于实现弹簧动画。

CASpringAnimation的重要属性:

  • mass:质量(影响弹簧的惯性,质量越大,弹簧惯性越大,运动的幅度越大)
  • stiffness:弹性系数(弹性系数越大,弹簧的运动越快)
  • damping:阻尼系数(阻尼系数越大,弹簧的停止越快)
  • initialVelocity:初始速率(弹簧动画的初始速度大小,弹簧运动的初始方向与初始速率的正负一致,若初始速率为0,表示忽略该属性)
  • settlingDuration:结算时间(根据动画参数估算弹簧开始运动到停止的时间,动画设置的时间最好根据此时间来设置)
        let scaleDown = CASpringAnimation(keyPath: "transform.scale")
        scaleDown.fromValue = 1.5
        scaleDown.toValue = 1.0
        
        // settlingDuration:结算时间(根据动画参数估算弹簧开始运动到停止的时间,动画设置的时间最好根据此时间来设置)
        scaleDown.duration = scaleDown.settlingDuration
        // mass:质量(影响弹簧的惯性,质量越大,弹簧惯性越大,运动的幅度越大) 默认值为1
        scaleDown.mass = 10.0
        // stiffness:弹性系数(弹性系数越大,弹簧的运动越快)默认值为100
        scaleDown.stiffness = 1500.0
        // damping:阻尼系数(阻尼系数越大,弹簧的停止越快)默认值为10
        scaleDown.damping = 50
        // initialVelocity:初始速率(弹簧动画的初始速度大小,弹簧运动的初始方向与初始速率的正负一致,若初始速率为0,表示忽略该属性)默认值为0
        scaleDown.initialVelocity = 100
        
        dogImageView.layer.addAnimation(scaleDown, forKey: nil)

5.总结

这一篇介绍了CABasicAnimation,以及子类CAAnimationGroup,CASpringAnimation的基本使用.

本文整理自 : iOS.Animations.by.Tutorials.v2.0
源码 : https://github.com/DarielChen/DemoCode
如有疑问,欢迎留言 :-D

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容