转载

【iOS】Animation Tips

前不久看完 Ray 的 《iOS Animations by Tutorials》,加上最近写动画的小心得,总结了几个 Tips。并不包含很难的动画效果,都是一些很基础的,但是有时候又不容易想到的实现方式(或者只是我没想到而已…)。这个 Tips 会持续更新。

因为这里的动画都是我从项目中抽出来的,所以对大家来说,这可能不是最佳实践。具体需求还是要具体分析,这里仅仅提供一种思路。

完整代码下载:

https://github.com/saitjr/STAnimationTips.git

环境信息:

Mac OS X 10.11.3

Xcode 7.2.1

iOS 9.2

一、多个视图的动画有序且无限次执行

【iOS】Animation Tips

动画循环周期如下:

(黑色放大 —— 橘色旋转一周 —— 黑色缩小)

【iOS】Animation Tips

对我的需求来说,最简单的做法是:黑色做动画,橘色等待;橘色动画完成后,黑色动画 reverse。

假设黑色动画时长是 scaleAnimationDuration ,橘色动画的时长是 rotateAnimationDuration

  1. 橘色动画第一次执行,要先等待黑色动画执行完。可以用  beginTime  来达到效果;
  2. 黑色动画先放大,后缩小,可以直接使用  autoreverses = true  ;
  3. 我当时遇到的最大的问题,是如何设置等待,因为这个动画中,出现最多的就是等待。

后来发现并不难,等待可以通过在当前的  scaleAnimation 和  rotateAnimation 外面包一个  groupAnimation  来达到效果。

如图(以  scaleAnimation  为例):

【iOS】Animation Tips

如图,在剩下的  groupDuration - scaleDuration 中,将没有动画效果,从而达到等待的目的。接下来便是计算时间。

依然以  scaleAnimation  为例,有几个属性需要注意(rotate 动画同理):

  1. scale 的  duration
  2. scale group 的  duration
  3. 谁来设置  autoreverses
  4. 谁来设置  repeatCount

先说  autoreverses ,如果是 scale 设置,那么执行完放大动画后,并不会等待,而是直接反向,所以,这个属性不能由 scale 设置,而应该由 scale group 来设置。

然后  repeatCount 和  autoreverses 原因大致类似,group 不重复,scale 重复再多也没用。

scale 的  duration 是可以随心所欲的。但是 scale group 的  duration 就需要注意了。

如下图,我大致整理了 scale 和 rotate 之间的关系。

红色为自定义的已知量,黑色为 scale 的相关数据,黄色为 rotate 的相关数据。

来说一下最后 rotate 的时间超出周期范围(虚线框) 的原因: beginTime  只在第一次执行动画的时候有效,所以 rotate 的等待时间应该要把【缩小+放大】的时间让出来。即 scale duration 的两倍。

【iOS】Animation Tips

这一步要仔细思考下,并不难。可以得到以下公式:

let scaleAnimationDuration: NSTimeInterval = 1.0 let rotateAnimationDuration: NSTimeInterval = 3.0  let scaleGroupAnimationDuration = rotateAnimationDuration / 2.0 + scaleAnimationDuration let rotateGroupAnimationDuration = rotateAnimationDuration + scaleAnimationDuration * 2.0 

好了,最繁琐的地方已经过了,下面就是写代码了。

// 执行旋转的橘色视图 private func orangeViewAnimation() {     let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation")     rotateAnimation.fromValue = -M_PI * 2     rotateAnimation.duration = rotateAnimationDuration      let groupAnimation = CAAnimationGroup()     groupAnimation.beginTime = CACurrentMediaTime() + scaleAnimationDuration     groupAnimation.duration = rotateAnimationDuration + scaleAnimationDuration * 2     groupAnimation.repeatCount = Float.infinity     groupAnimation.animations = [rotateAnimation]     orangeView.layer.addAnimation(groupAnimation, forKey: "rotateAnimation") }  // 执行缩放的黑色视图 private func blackViewAnimation() {     let scaleAnimation = CABasicAnimation(keyPath: "transform.scale")     scaleAnimation.fromValue = 1     scaleAnimation.toValue = 0.5     // 因为在放大以后,要停留在放大的状态,等待橘色视图旋转,所以使用 fillMode 和 removedOnCompletion 两个属性来将动画停留在最终的状态     scaleAnimation.fillMode = kCAFillModeForwards     scaleAnimation.removedOnCompletion = false     scaleAnimation.duration = scaleAnimationDuration      let groupAnimation = CAAnimationGroup()     groupAnimation.duration = scaleAnimationDuration + rotateAnimationDuration / 2.0     groupAnimation.repeatCount = Float.infinity     groupAnimation.autoreverses = true     groupAnimation.animations = [scaleAnimation]     blackView.layer.addAnimation(groupAnimation, forKey: "scaleAnimation") } 

第一个 Tips 就到这里。完整代码可以查看:

https://github.com/saitjr/STAnimationTips/blob/master/STAnimationTips/ViewControllers/GroupAnimationVC.swift

二、程序挂起动画被移除,程序唤醒时重新添加的处理

原文  http://www.saitjr.com/ios/ios-animation-tips.html
正文到此结束
Loading...