Layer Animation(一)

Monday, March 19, 2018

常用 layer 动画属性

Postion and Size

  • bounds
  • positions
  • transform

Border

  • borderColor
  • borderWidth
  • cornerRadius
  • shadowOffset
  • shadowOpacity
  • shadowRadius

Content

  • contents: TIFF or PNG 数据
  • mask
  • opacity

Layer 动画

[WPGP gif_id="114” width="400”]

  • 先说说最简单的位移动画

    let flyRight = CABasicAnimation(keyPath: “position.x”) flyRight.fromValue = -view.bounds.size.width/2 flyRight.toValue = view.bounds.size.width/2 flyRight.duration = 0.5 heading.layer.add(flyRight, forKey: nil)

  • 如此一来,heading 的 layer 层就添加了一个位移动画了,keyPath 是 position.x

    flyRight.beginTime = CACurrentMediaTime() + 0.3

  • 如果要延迟开始,可以用 CACurrentMediaTime()

fillMode

  • 重点讲讲 fillMode 的几个属性,KCAFillModeBackwards,KCAFillModeForward,KCAFillModeBoth
  • KCAFillModeBackwards 是动画的第一帧就展示出来,无论动画是不是从最开始来执行
  • KCAFillModeForward 是动画结束后,仍然展示动画的最后一帧
  • KCAFillModeBoth 则是上述两者的集合体。

动画和实体

  • 当我们看到上述textfield的动画时,其实并不是 textfiled 本身的动画,而是 textfield 的缓存也就是表示层(presentation layer),当动画结束后,就会被移除。textField 本身,在动画的时候,会暂时隐藏,等动画结束后,再显示出来。
  • 而这样就会导致一个问题,比如使用位移动画,本来已经从 A 点到 B 点了。但结束后,view 本身又会在原点出现,并没有在 B 点。
KCAFillModeForward and isRemovedOnCompletion
  • 鉴于此,很多人会使用上述两种属性来让 view 维持在 B 点。

    //例如加入了下面两行代码 flyRight.fillMode = kCAFillModeBoth flyRight.isRemovedOnCompletion = false

  • 加入上述代码后,确实能达到部分效果,但是,此时假如我们点击 textField,会发现根本没有响应。因为这并不是textField 本身,而只是一个presentation layer,你并不能在上面执行任何操作。

  • 所以我们要避免使用 isRemovedOnCompletion 这个参数,不但在某些情况下失效,还会影响性能。

  • 解决方案是,在添加完动画后,我们将 textField 的坐标设为目的地,这样,在动画结束后,textField 就会在终点显示出来了。

Animation Keys and Delegate

  • 两个常用的动画 delegate, animationDidStart 和 animationDidStop

    extension ViewController: CAAnimationDelegate { func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { print(“animation did finish”) } }

keyValue

  • 我们可以给动画设置 keyValue 键值访问

    flyRight.setValue(“form”, forKey: “name”) flyRight.setValue(heading.layer, forKey: “layer”)

  • 如此一来,我们便可以在delegate 中给特定 layer 进行特定的处理

    guard let name = anim.value(forKey: “name”) as? String else { return } if name == “form” { let layer = anim.value(forKey: “layer”) as? CALayer anim.setValue(nil, forKey: “layer”)

        let pulse = CABasicAnimation(keyPath: "transform.scale") pulse.fromValue = 1.25 
        pulse.toValue = 1.0 
        pulse.duration = 0.25 
        layer?.add(pulse, forKey: nil)
    

    }

  • 如此一来,动画会在结束后,再执行一个放大动画。

Groups and Advanced Timing

CAAnimationGroup

  • 我们可以尝试将三种动画组合到一起,例如fade,move,scale

    //首先初始化 groupAnimation let groupAnimation = CAAnimationGroup() groupAnimation.beginTime = CACurrentMediaTime() + 0.5 groupAnimation.duration = 0.5 groupAnimation.fillMode = KCAFillModeBackwards

    //设置 scale 动画 let scaleDown = CABasicAnimation(keyPath: “transform.scale”) scaleDown.fromValue = 3.5 scaleDown.toValue = 1.0

    //设置rotate 动画 let rotate = CABasicAnimation(keyPath: “transform.rotation”) rotate.fromValue = .pi / 4.0 rotate.toValue = 0.0

    //设置 fade 动画 let fade = CABasicAnimation(keyPath: “opacity”) fade.fromValue = 0.0 fade.toValue = 1.0

    //将动画组合起来 groupAnimaton.animations = [scaleDown, rotate, fade] loginButton.layer.add(groupAnimation, forKey: nil)

    //设置 TimingFunction,一样是 linear,easeIn,easeOut,easeIneaseOut groupAnimation.timingFunction = CAMediaTimingFunction(name: KCAMediaTimingFunctionEaseIn)

更多相关的属性
  • repeateCount
  • autoreverses
  • speed
  • repeateCount 和 autoreverses 配合使用时,可以降 repeateCount 设置为.5的次数,例如2.5,这样可能才会达到你想要的效果。
iOS动画

Layer Animation(二)

Auto layout Animation