ios7新特性--15

介绍
自从IOS2开始,UIView已经有了动画方法,在IOS4添加基于块的API。这些方法是对下层CoreAnimation层的封装,UIView的实例基于这个渲染。

UIView的动画制作的方法允许一些动画属性(例如transform, backgroundColor,frame, center等等 )设置最终状态,持续时间和其他选项例如动画曲线。然而,动画中设置中间状态,所谓键帧,还是不可能的。这种情况下,需要进入底层CoreAnimation并创建CAKeyFrameAnimation。在IOS7改变了,UIView新增两个方法,不用进入底层CoreAnimation就可以支持键帧动画了。

为了演示如何使用UIView键帧动画,我们将创建2个使用键帧动画的demo。第一个动画demo是将视图的背景色按彩虹颜色改变,第二个动画demo指定旋转方向,演示了360度旋转。

彩虹变换器
UIView键帧动画需要2个方法,第一个方法类似于另一个基于块的方法 animateKeyframesWithDuration:delay:options:animations:completion:。这个方法包括float类型的duration和delay,位掩码options,animation和completion块,所有都是UIView动画世界里优美的标准。我们调用的方法与这个方法不同的地方是动画块: addKeyframeWithRelativeStartTime:relativeDuration:animations:。这个方法被用来在动画序列中添加固定的点。

理解这个方法最好的方式就是演示它。我们将创建一个动画,按彩虹色彩动画处理UIView的背景色(在我们开始彩虹颜色变化之前,我已经做了一个任意的选择,恰好也是正确的)。要通过点击按钮触发这个动画,所以我在stroyboard上添加了一个按钮,并与下面的方法关联:
- (IBAction)handleRainbow:(id)sender { [self enableToolbarItems:NO]; void (^animationBlock)() = ^{ // Animations here}; [UIView animateKeyframesWithDuration:4.0delay:0.0options:UIViewKeyframeAnimationOptionCalculationModeLinear | UIViewAnimationOptionCurveLinear animations:animationBlock completion:^(BOOL finished) { [self enableToolbarItems:YES]; }]; }

创建动画animationBlock的局部变量,然后调用animateKeyframesWithDuration:delay:options:animations:completion:方法。使用下面的方法,当动画开始时,禁用工具栏按钮,动画结束时,启用按钮:
- (void)enableToolbarItems:(BOOL)enabled { for (UIBarButtonItem *item in self.toolbar.items) { item.enabled = enabled; } }

在稍后处理键帧动画时,我们将先看一下一些可选项,现在让我们填充动画块:
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 ; }]; } }; 

开始我们需要创建动画颜色数组,然后循环遍历每一个。针对每个颜色,我们调用一个方法添加键帧到动画上。
[UIView addKeyframeWithRelativeStartTime:i/(CGFloat)colorCount relativeDuration:1/(CGFloat)colorCount animations:^{ self.rainbowSwatch.backgroundColor = rainbowColors; }];

对每个键帧,我们定义了开始时间,持续时长和动画块。时间是相对的,也就是说,它的取值范围是(0,1)的float值,会根据动画时长来获取合适的比例。这里我们希望动画期间颜色均匀变化,所以我们设置每个动画relative start time为当前动画索引除以颜色的数量,relatvie duration为1除以颜色的数量。animation block定义结束状态,并以同样的方式对待所有UIView基于块的动画,所以这里我们仅仅需要设置背景色。

如果你运行上面的应用,并点击‘Rainbow’按钮,那么你将在实际中看到你的第一个键帧动画。
ios7新特性--15_第1张图片 


键帧动画选项
animateKeyFrames:方法的选项参数是UIViewAnimationOptions类型的,连同在UIViewKeyframeAnimationOptions定义的一些新值,特别在动画阶段设置动画曲线。下面就是在这个行为中给予的一些选项:
UIViewKeyframeAnimationOptionCalculationModeLinear UIViewKeyframeAnimationOptionCalculationModeDiscrete UIViewKeyframeAnimationOptionCalculationModePaced UIViewKeyframeAnimationOptionCalculationModeCubic UIViewKeyframeAnimationOptionCalculationModeCubicPaced
下面图显示不同的选项如何控制动画的。水平轴代表动画时间,垂直轴代表正在动画的一维参数(可能视图的alpha,或者frame的width)。这个示例中我们定义了3个键帧,每一个都有不同的持续时长和结束状态。

 

具体的看一下每个选项:
1、Linear 键帧之间的转换是线性内插值替换的,像上面图中红色的。这意味着一个动画可以出现加速和减速,因为动画是增量变化的。
2、Discrete 在每个键帧结束的时候瞬时转换,像上面图中蓝色的。这种情况下,实际上是没有动画的,仅仅是跳到另个键帧上。
3、Paced 一个简单的算法使键帧动画点上匀速执行
4、Cubic 键帧点之间画立方样条,然后动画沿着这条线,上图绿色的部分。这可能导致在开始时动画朝相反的方向。
5、CubicPaced 这忽略了键帧动画中定义的定时,强制不同键帧位置之间匀速执行。例如粉红色的部分。这将导致动画看起来匀速平滑,但是会忽略你开始设置的动画时间。
我不建议discrete选项。值得在你的例子中把玩不同的选项。因为算法是完全黑盒的,你无法控制它们的参数,试图全面了解它们的运作也是有点徒劳的。这种情况下实际验证是非常有意义的(通常这样不是很好,最好实际的了解每个选项的不同,而不是靠猜测)。

旋转方向
作为一个白送的例子,我们也去看看如何旋转视图,并指定方向。当你定义一个动画时,CoreAnimation将从开始状态到结束状态执行一个最短动画路径。因此对旋转变换,我们只能定义开始角度和结束角度,但不能指定旋转方向。键帧动画能克服这个问题,可以定义一些中间状态。
因此对于一个顺时针方向完全旋转我们可以编写以下方法:
-        (IBAction)handleRotateCW:(id)sender { [self enableToolbarItems:NO]; [UIView animateKeyframesWithDuration:2.0delay:0.0options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{ [UIView addKeyframeWithRelativeStartTime:0.0relativeDuration:1/3.0animations:^{ self.rotatingHead.transform = CGAffineTransformMakeRotation(2.0 * M_PI / 3.0); }]; [UIView addKeyframeWithRelativeStartTime:1/3.0relativeDuration:1/3.0animations:^{ self.rotatingHead.transform = CGAffineTransformMakeRotation(4.0 * M_PI / 3.0); }]; [UIView addKeyframeWithRelativeStartTime:2/3.0relativeDuration:1/3.0animations:^{ self.rotatingHead.transform = CGAffineTransformMakeRotation(0); }]; } completion:^(BOOL finished) { [self enableToolbarItems:YES]; }]; }
我们用3种状态执行一个键帧动画,在动画过程中3个状态时间相等。开始旋转角度为0,然后在结束重回到0前移到 2π/3, 4π/3。为了完全指定旋转2π,我们需要2个中间固定点。只要一个角的差大于π,它将会朝相反方向旋转。当一个角的差正好等于π时,行为是未定义的。

ios7新特性--15_第2张图片 

为了改变旋转方向,我们只需要反转键帧,也就是说,从0开始,然后移动到4π/3, 2π/3,最后到0。
- (IBAction)handleRotateCCW:(id)sender { [self enableToolbarItems:NO]; [UIView animateKeyframesWithDuration:2.0delay:0.0options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{ [UIView addKeyframeWithRelativeStartTime:0.0relativeDuration:1/3.0animations:^{ self.rotatingHead.transform = CGAffineTransformMakeRotation(4.0 * M_PI / 3.0); }]; [UIView addKeyframeWithRelativeStartTime:1/3.0relativeDuration:1/3.0animations:^{ self.rotatingHead.transform = CGAffineTransformMakeRotation(2.0 * M_PI / 3.0); }]; [UIView addKeyframeWithRelativeStartTime:2/3.0relativeDuration:1/3.0animations:^{ self.rotatingHead.transform = CGAffineTransformMakeRotation(0); }]; } completion:^(BOOL finished) { [self enableToolbarItems:YES]; }]; }
忍者的忍者头可以旋转在顺时针或逆时针方向——无需进入CoreAnimation层。

总结
UIView的动画总是以高级的方式去执行简单的视图动画,异常简单的理解和应用。现在,通过增加的键帧动画,可以以简单的API实现更复杂的动画。本文演示了它是多么的强大,还有一些琐碎的例子(虽然旋转方向是一种常见的需求)。

你可能感兴趣的:(ios7新特性--15)