0%

iOS Animation Swift 版

coreAnimation

简介

此文主要记录我学习 iOS 的动画相关内容用 Swift 语言,记录下来以供参考,不定时更新。

目录结构

  • Section I: View 动画
  • View animation
  • 弹簧动画 - Springs
  • 转场动画 - Transitions
  • 关键帧动画 - Keyframe
  • Section II: Auto Layout 动画
  • Section III: Layer 动画
  • Section IV: 3D 动画
  • Section V: 未来类型的动画
  • Section VI: View Controller 动画
  • Section VII:第三方动画库
  • Section VIII: Apple Watch 动画

Section I: View 动画

1.View animation

简介:view 的动画主要是通过 UIView 的类方法创建,动画内容一般
放在 block 里面,可以镶嵌使用,构成链式动画,主要有 3 个方法,三个访法只需会参数最多的那个就行,函数名 animateWithDuration(_:delay:options:animations:completion:) ,其他的使用起来都类似。

1
2
3
class func animateWithDuration(_ duration: NSTimeInterval, animations animations: () -> Void)
class func animateWithDuration(_ duration: NSTimeInterval, animations animations: () -> Void, completion completion: ((Bool) -> Void)?)
class func animateWithDuration(_ duration: NSTimeInterval, delay delay: NSTimeInterval, options options: UIViewAnimationOptions, animations animations: () -> Void, completion completion: ((Bool) -> Void)?)

使用:

1
2
3
4
5
UIView.animateWithDuration(0.5, delay: 0, options: [], animations: {
//do something
}, completion: {_ in
//do something
})

说明: options ,动画选项,这个运行你设置一个动画选项集合,传 [] 表示不需要选项,单个时可以省略放括号例如 .Repeat ,多个用逗号连接 [.Repeat, .CurveEaseInOut] > completion 闭包需要一个参数,不需要使用参数可以用 _ 表示,不需要实现可以直接传 nil 或者像下面这样写

1
2
3
4
5
UIView.animateWithDuration(0.5, delay: 0, options: [], animations: { () -> Void in
//do something
}) { (_) -> Void in
//do something
}
2.弹簧动画 - Springs

简介:弹簧动画是 iOS 7.0 新增的 API,函数名 animateWithDuration(_:delay:usingSpringWithDamping:initialSpringVelocity:opti ons:animations:completion:)

1
class func animateWithDuration(_ duration: NSTimeInterval, delay delay: NSTimeInterval, usingSpringWithDamping dampingRatio: CGFloat, initialSpringVelocity velocity: CGFloat, options options: UIViewAnimationOptions, animations animations: () -> Void, completion completion: ((Bool) -> Void)?)

使用:

1
2
3
UIView.animateWithDuration(0.5, delay: 0.5, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.0, options: [], animations: {
// do something
}, completion: nil)

说明: usingSpringWithDamping :设置弹簧的阻尼,范围(0.0-1.0),越接近 0.0 弹簧越有弹性,越接近 1.0,效果越僵硬,你可以把当成弹簧的刚度来理解,
initialSpringVelocity :设置弹簧初始化的速度,设置 1.0 表示用 1 秒在动画跨度上完成整个动画距离,值越大或者越小会导致动画有相应的大的或者较小的速度,可以当成弹簧的初始动量来理解。

3.转场动画 - Transitions

简介:前两种创建的动画是基于可动画的接口例如,position,alpha,frame 等等,Transitions 是专门处理添加或者移除一个 view 的动画,系统有 2 个标准函数,一个是对单个 view 的处理,一个是处理 2 个 view 替换。

1
2
class func transitionWithView(_ view: UIView, duration duration: NSTimeInterval, options options: UIViewAnimationOptions, animations animations: (() -> Void)?, completion completion: ((Bool) -> Void)?)
class func transitionFromView(_ fromView: UIView, toView toView: UIView, duration duration: NSTimeInterval, options options: UIViewAnimationOptions, completion completion: ((Bool) -> Void)?)

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//add the new view via transition
UIView.transitionWithView(animationContainerView!, duration: 0.33,
options: [.CurveEaseOut, .TransitionFlipFromBottom], animations: {
self.animationContainerView!.addSubview(newView) }, completion: nil)

//remove the view via transition
UIView.transitionWithView(animationContainerView!, duration: 0.33,
options: [.CurveEaseOut, .TransitionFlipFromBottom], animations: {
self.newView.removeFromSuperview() }, completion: nil)

//hide the view via transition
UIView.transitionWithView(self.newView, duration: 0.33, options: [.CurveEaseOut, .TransitionFlipFromBottom], animations: {
self.newView.hidden = true }, completion: nil)

//replace via transition
UIView.transitionFromView(self.oldView!, toView: self.newView!, duration: 0.33, options: [.TransitionFlipFromTop],
completion: nil)
4.关键帧动画 - Keyframe

简介:关键帧顾名思义就是设定关键的一些帧然后系统会根据一套算法计算中间的其他帧,这样改变的可动画属性时看看起来更加流畅自然,主要有两个函数,一个创建关键帧动画,一个设置具体每帧内容

1
2
class func animateKeyframesWithDuration(_ duration: NSTimeInterval, delay delay: NSTimeInterval, options options: UIViewKeyframeAnimationOptions, animations animations: () -> Void, completion completion: ((Bool) -> Void)?)
+ (void)addKeyframeWithRelativeStartTime:(double)frameStartTime relativeDuration:(double)frameDuration animations:(void (^)(void))animations

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
func planeDepart() {

UIView.animateKeyframesWithDuration(1.5, delay: 0.0, options: [], animations: {
//add keyframes

UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration: 0.25, animations: {
self.planeImage.center.x += 100.0
self.planeImage.center.y -= 10.0
})

UIView.addKeyframeWithRelativeStartTime(0.1, relativeDuration: 0.4) {
self.planeImage.transform = CGAffineTransformMakeRotation(CGFloat(-M_PI_4/2))
}

UIView.addKeyframeWithRelativeStartTime(0.25, relativeDuration: 0.25) {
self.planeImage.center.x += 100.0
self.planeImage.center.y -= 60.0
self.planeImage.alpha = 0.0
}

UIView.addKeyframeWithRelativeStartTime(0.51, relativeDuration: 0.01) {
self.planeImage.transform = CGAffineTransformIdentity
self.planeImage.center = CGPoint(x: 0.0, y: originalCenter.y)
}

UIView.addKeyframeWithRelativeStartTime(0.55, relativeDuration: 0.45) {
self.planeImage.alpha = 1.0
self.planeImage.center = originalCenter
}

}, completion: nil)
}

说明:这是设计一个飞机沿一条路径起飞然后再归位的一段动画, addKeyframeWithRelativeStartTime(_:relativeDuration:animations:) ,第一个参数相对开始时间,是相对于动画持续时间的百分比,例如 0.1 就是 10%,0.25 就是 25%,如果整个动画持续 2 秒,0.1 就是在 2*0.1=0.2 秒的时候开始,后面的一个参数是相对持续时间,范围更第一参数类似也(0.0-1.0),只从相对开始时间起,往后推移的相对时间。

Section II: Auto Layout 动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

// change Constraint

// init layout
view.layoutIfNeeded()

UIView.animateWithDuration(0.8, delay: 0.0,
usingSpringWithDamping: 0.4, initialSpringVelocity: 0.0,
options: [], animations: {

// do something change constraint

// layout
self.view.layoutIfNeeded()
}, completion: nil)

原理就是,修改约束,让添加一个动画,在动画 block 里面执行布局更新, block 里面也可以添加修改约束代码,修改约束的本质是修改相关 Viewframebounds ,由于修改 View 的这个属性是支持动画的,所以修改约束其实是间接修改 View 的这些属性,所以也是支持动画的,这个动画的强大的之处在于,可以实现一系列 View 相互协作的动画。

Section VIII: Apple Watch 动画

概述:在 Apple Watch 中有两种技术来创建动画,一个是一次性创建一系列静态可动画的图片序列或者循环动画,另一种是对标签和其他项目通过改变尺寸,对齐,颜色,透明度进行布局和外观动画。

Animated Image Sequences

Animated Image Sequences 是由两个或者更多的独立图片组成的序列来随时间按序列显示。每张图片组成了动画的一个单独的帧,整个动画运行在一个循环中除了你在运行的时候修改了播放的行为。主要把它安装在你界面中的 imagegroup , button 等元素中。通过 WKImageAnimatable 协议来实现动画,也就是说凡是遵循这个协议的对象都支持动画, WatchKit 中遵循这个协议的对象有: WKInterfaceGroupWKInterfaceImage 你可以控制 imagegroup 元素 Animated Image Sequences 的播放的速度,方向,帧率,否则界面元素将会无限循环显示一个完整的动画。

Notes:

  1. Animated Image Sequences 可以正向播放动画也可以反向执行动画在运行的时候,你不应该提供一套一样的图片以反向的方式,你应该使用这个技术来降低 App 的尺寸。
  2. 如果你是从 storyboard 创建序列图片对象,可以通过 func startAnimating() 方法开始执行动画,通过 func stopAnimating() 来停止动画的执行。

实例:

实现 WKInterfaceGroup 加载进度动画

1.在 Watch 里面的 Interface.storyboard 里面拖拽一个 WKInterfaceGroup 命名为 backgroundGroup 2.创建一个 WKInterfaceButton 按钮来触发这个动画事件,在控制器里面实现下面的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@IBAction func checkInButtonTapped() {
// 1
let duration = 0.35
let delay = dispatch_time(DISPATCH_TIME_NOW, Int64((duration + 0.15) * Double(NSEC_PER_SEC)))
// 2
backgroundGroup.setBackgroundImageNamed("Progress")
// 3
backgroundGroup.startAnimatingWithImagesInRange(NSRange(location: 0, length: 10), duration: duration, repeatCount: 1)
// 4
dispatch_after(delay, dispatch_get_main_queue()) { () -> Void in
// 5
dosomething
}
}

参数说明: imageRange ,将要执行动画的图片范围, 0 表示第一张图片, 1 表示第二张图片,以此类推; duration ,单位秒,表示动画执行单个循环的时间, 正值 表示从第一帧到最后一帧执行, 负值 表示以相反的顺序执行动画,以第一帧结束; repeatCount ,动画的重复次数,设置 0 表示无限循环。

3.将素材文件拖入 WatchAsset.xcassets 的文件里面,以 Progress 开始命名后面接一串连续的数字,效果应该像下面这样。

iWatchProgress

4.然后在模拟器上运行就 OK 了。

Layout and Appearance Animations

你可以动画改变所有界面元素的布局和外观。动画改变布局让你修改元素的尺寸或者动态的改变布局的方向。你可以移动在屏幕上的元素或者让它们的内容重新对齐。你也可以动画改变元素的外观,包括改变他们的 backgroud color 或者 opactiy 。这些类型的动画让你创建动态的界面用来响应用户的交互并且提供一个更好的反馈。

所有的 layout- and appearance-based animations 在动画开始和结束都以 easing 的曲线方式自动构建 。你不能关闭或者自定义缓动曲线。相当于 UIView 的动画选项里面的 easeInOut

可动画属性:

  • Opacity
  • Height
  • Width
  • Group Insets
  • Alignment
  • Background Color
  • Tint Color

核心代码:

1
2
3

class func animateWithDuration(_ duration: NSTimeInterval, animations animations: () -> Void)

说明:这个方法在 WKInterfaceController 中,目前发现只有这一个动画 API,你可以在这个闭包里面执行相应的动画操作,实现跟 UIView 的 block 动画类似。

iWatchAnimation

实例:

在界面已经出现的时候对 planeImage 进行着色动画,改变 separator 的颜色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

var planeImage: WKInterfaceImage!
var separator: WKInterfaceSeparator!

override func didAppear() {
super.didAppear()
// 1
animateWithDuration(0.35, animations: { () -> Void in
// 2
let color = UIColor(red: 90/255, green: 200/255, blue: 250/255, alpha: 1)
planeImage.setTintColor(color)
separator.setColor(color)
})
}
}

参考资料:

备注:欢迎转载,但请一定注明出处! http://blog.wangruofeng007.com