这篇文章是天天品尝iOS7甜点系列的一部分,你可以查看完整的系列目录:天天品尝iOS7甜点
Introduction – 介绍
从iOS2开始, UIView
就有了实现动画的方法,而在iOS4中就添加了运用block的方法。这些方法都是对 CoreAnimation
层的一个装饰方法, UIView
只是通过实例渲染的。
UIView
中的实现动画的方法允许一下可以设置为动画的属性(例如transform
, backgroundColor
, frame
, center
等)——设置成为最终状态,运行时长和其他的一些运动曲线的选项。然而,设置中间动画的中间状态(被称之为关键帧),是不可能办到的。在这种情况下有必须运用 CoreAnimation
来创建一个 CAKeyFrameAnimation
.在iOS7中包含了这些变化,在 UIView
中新增了两个方法,所以不需要自己借助于 CoreAnimation
就可以实现关键这动画了。
为了展示如何通过 UIView
来实现关键帧动画,我们需要创建一些示例程序。首先通过彩虹的颜色改变视图背景颜色的动画,其次演示一个指定旋转方向的360旋转示例。
本章的实例程序能够在github上面进行访问,访问地址:github.com/ShinobiControls/iOS7-day-by-day
Rainbow Changer – 彩虹变色器
UIView
的关键帧动画需要用到两个方法,首先一个比较熟悉的block方法是animateKeyframesWithDuration:delay:options:animations:completion:
这个方法需要浮点类型的动画持续时长(duraiton)和延迟(delay),一些二进制组成的选项(options)和动画运行的block和动画运行完成最后的block,这是一个标准的UIView
的动画的实现。下一次有点儿不同的方法我们称之为内部块方法:addKeyframeWithRelativeStartTime:relativeDuration:
。这个方法是用来添加动画序列内的不动点。
我们通过一个示例来理解用法。我们需要创建一个通过彩虹颜色变化视图背景色的动画,我们将着重显示按钮点击之后的动画。所以我们需要在storyboard中添加一个按钮,并且把它绑定到下面的方法上面:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 |
- (IBAction)handleRainbow:(id)sender { [self enableToolbarItems:NO]; void (^animationBlock)() = ^{ // Animations here }; [UIView animateKeyframesWithDuration:4.0 dylay:0.0 options:UIViewKeyframeAnimationOptionCalculationModeLinear|UIViewAnimationOptionCurveLinear animations:animationBlock completion:^(BOOL finished) { [self enableToolbarItems:YES]; }]; } |
这里我们创建一个包含动画的局部变量 animationBlock
,然后调用animateKeyframesWithDuration:delay:options:animations:completion:
方法。让我们开始运行动画之前,显示禁用按钮,然后等到动画运行完成之后,在开启按钮,具体的实现如下:
1
2
3
4
5 |
- (void)enableToolbarItems:(BOOL)enabled { for (UIBarButtonItem *item in self.toolbar.items) { item.enable = enabled; } } |
我们会看一些可用的选项在执行帧动画后,现在让我们填写动画块:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 |
void (^animationBlock)() = ^{ NSArray *rainbowColors = @[[UIColor orangeColor], [UIColor yellowColor], [UIColor greenColor], [UIColor blueColor], [UIColor purpleColor], [UIColor redColor]]; NSUInteger colorCount = [rainbowColors count]; for(NSUInteger i=0; i<colorCount; i++) { [UIView addKeyframeWithRelativeStartTime:i/(CGFloat)colorCount relativeDuration:1/(CGFloat)colorCount animations:^{ self.rainbowSwatch.backgroundColor = rainbowColors[i]; }]; } }; |
首先我们创建了一个装有所有变换颜色的数组,每一个颜色我们通过调用下面的方法来实现关键帧的动画效果:
1
2
3
4
5 |
[UIView addKeyframeWithRelativeStartTime:i/(CGFloat)colorCount relativeDuration:1/(CGFloat)colorCount animations:^{ self.rainbowSwatch.backgroundColor = rainbowColors[i]; }]; |
每一帧动画我们都指定了一个开始时间,持续时间和一个动画运行块(block).这些时间都是相对的,也就是,我们指定浮点数在0到1之间,然后他们将会适当的自己去匹配动画的运行时长。这里我们想要的颜色变化等间距的整个动画,所以我们设置相对每个动画的开始时间是指数当前的颜色在颜色的总数,和相对时间是1的总数的颜色。动画块指定动画的最终状态,以同样的方式确实对所有UIView基于块的动画,这里我们只需要设置背景颜色。
如果你运行app,并且点击 Rainbow
按钮,然后你就可以看到第一个视图执行关键帧动画。
Keyframe animation options – 关键帧动画的选项参数设置
方法 animateKeyFrames:
中的选项介绍 UIViewAnimationOptions
参数,尽管在 UIViewKeyFrameAnimationOptions
中有一些新的值,下面就是控制这些行为的选项:
1
2
3
4
5 |
UIViewKeyframeAnimationOptionCalculationModeLinear UIViewKeyframeAnimationOptionCalculationModeDiscrete UIViewKeyframeAnimationOptionCalculationModePaced UIViewKeyframeAnimationOptionCalculationModeCubic UIViewKeyframeAnimationOptionCalculationModeCubicPaced |
下图展示不同选项行为上面的不同。水平轴代表了动画的时长,而竖直轴代表动画的参数(这可以是视图的透明度,宽度),在示例中,我们已经指定了3个关键帧,每一个都有不同的时长和最终值.
上述参数的运行效果,可以在图中进行查看,不同颜色的线条,代表不同的选项对应的运行效果。
Rotation Directions – 旋转方向
上面已经写了一大推的代码了,我们还需要查看如何指定整个视图的旋转,指定旋转方向。当你指定一个动画,然后 CoreAnimation
将会以最短的路径记录开始和结束。因此,在进行旋转变换的时候,我们只需要指定开始的角度和结束的角度,但不是它会旋转的方向。使用关键帧动画,我们可以一些中间的状态。
因此,一个顺时针的旋转,我们可以写法如下:
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 |
- (IBAction)handleRotateCW:(id)sender { [self enableToolbarItems:NO]; [UIView animateKeyframesWithDuration:2.0 delay:0.0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{ [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:1/3.0 animations:^{ self.rotatingHead.transform = CGAffineTransformMakeRotation(2.0 * M_PI / 3.0); }]; [UIView addKeyframeWithRelativeStartTime:1/3.0 relativeDuration:1/3.0 animations:^{ self.rotatingHead.transform = CGAffineTransformMakeRotation(4.0 * M_PI / 3.0); }]; [UIView addKeyframeWithRelativeStartTime:2/3.0 relativeDuration:1/3.0 animations:^{ self.rotatingHead.transform = CGAffineTransformMakeRotation(0); }]; } completion:^(BOOL finished) { [self enableToolbarItems:YES]; }]; } |
我们执行关键帧动画有3个中间态,整个动画的持续时间是等距的。我们选择的开始角度是0,然后我们移动到2π/3, 4π/3,最后再次回到0。为了完成指定的2π的旋转,我们需要有额外的2个中间点,因为只要有一个角度的差异大于π那么它将相反的方向旋转。如果一个角度的差异就是π,那么行为就是未定义的。
为了改变旋转的方向,我们需要反转关键帧,也就是,开始的角度为0,然后移动到4π/3, 接着2π/3,最后再次回到0:
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 |
- (IBAction)handleRotateCCW:(id)sender { [self enableToolbarItems:NO]; [UIView animateKeyframesWithDuration:2.0 delay:0.0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{ [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:1/3.0 animations:^{ self.rotatingHead.transform = CGAffineTransformMakeRotation(4.0 * M_PI / 3.0); }]; [UIView addKeyframeWithRelativeStartTime:1/3.0 relativeDuration:1/3.0 animations:^{ self.rotatingHead.transform = CGAffineTransformMakeRotation(2.0 * M_PI / 3.0); }]; [UIView addKeyframeWithRelativeStartTime:2/3.0 relativeDuration:1/3.0 animations:^{ self.rotatingHead.transform = CGAffineTransformMakeRotation(0); }]; } completion:^(BOOL finished) { [self enableToolbarItems:YES]; }]; } |
这样忍者的头部就可以自由的选择,更重要的一点是,我们并没有使用底层的CoreAnimation
Conclusion – 总结
UIView
动画已经具有高级的方法来执行简单的动画,并且能够更好的理解和构建。现在,有了新的关键帧动画,更多复杂的动画可以使用相同的简单API。本篇文章通过几个示例介绍了它是多么的强大。
本文翻译自: iOS7 Day-by-Day :: Day 11 :: UIView Key-frame Animations