美文网首页
iOS中高级动画技巧

iOS中高级动画技巧

作者: 浪呀么浪打浪 | 来源:发表于2020-07-08 20:27 被阅读0次

有很多方法可以配置基于属性的动画或关键帧动画,以为您做更多的事情。需要一起或顺序执行多个动画的应用可以使用更高级的行为来同步这些动画的时间或将它们链接在一起。您还可以使用其他类型的动画对象来创建视觉过渡和其他有趣的动画效果。

过渡动画支持对图层可见性的更改

顾名思义,过渡动画对象为图层创建了动画的视觉过渡。过渡对象最常见的用途是以一种协调的方式为一层的外观和另一层的消失设置动画。与基于属性的动画不同,在动画中,动画会更改图层的一个属性,而过渡动画会操纵图层的缓存图像以创建视觉效果,而仅通过更改属性就很难或不可能做到。使用标准的过渡类型,您可以执行显示,推动,移动或淡入淡出动画。在OS X上,您还可以使用Core Image过滤器创建使用其他类型的效果(例如划像,页面卷曲,波纹或您设计的自定义效果)的过渡。

要执行过渡动画,请创建一个CATransition对象并将其添加到过渡所涉及的图层中。您可以使用过渡对象来指定要执行的过渡类型以及过渡动画的起点和终点。您也不需要使用整个过渡动画。过渡对象使您可以指定动画时要使用的开始和结束进度值。这些值使您可以执行诸如在动画的中点开始或结束动画之类的操作。

清单5-1显示了用于在两个视图之间创建动画推送过渡的代码。在示例中,myView1和和myView2都位于同一父视图中的相同位置,但仅myView1当前可见。按下过渡会导致myView1向左滑出并逐渐消失,直到它被隐藏,而myView2从右侧滑入并变为可见。更新两个视图的hidden属性可确保在动画结束时两个视图的可见性正确。

单5-1 为iOS中两个视图之间的过渡设置动画

CATransition * transition = [CATransition animation];

transition.startProgress = 0;

transition.endProgress = 1.0;

transition.type = kCATransitionPush;

transition.subtype = kCATransitionFromRight;

transition.duration = 1.0;

//将过渡动画添加到两个图层

[myView1.layer addAnimation:transition forKey:@“ transition”];

[myView2.layer addAnimation:transition forKey:@“ transition”];

//最后,更改图层的可见性。

myView1.hidden = YES;

myView2.hidden = NO;

当同一转换涉及两个图层时,可以对两个图层使用相同的转换对象。使用相同的过渡对象还可以简化您必须编写的代码。但是,您可以使用不同的过渡对象,并且如果每个图层的过渡参数都不同,则肯定需要这样做。

清单5-2显示了如何使用Core Image滤镜在OS X上实现过渡效果。在为滤镜配置了所需的参数之后,将其分配给filter过渡对象的属性。此后,应用动画的过程与其他类型的动画对象相同。

清单5-2 使用Core Image过滤器为OS X上的过渡设置动画

//创建Core Image过滤器,设置几个关键参数。

CIFilter * aFilter = [CIFilter filterWithName:@“ CIBarsSwipeTransition”];

[aFilter setValue:[NSNumber numberWithFloat:3.14] forKey:@“ inputAngle”];

[aFilter setValue:[NSNumber numberWithFloat:30.0] forKey:@“ inputWidth”];

[aFilter setValue:[NSNumber numberWithFloat:10.0] forKey:@“ inputBarOffset”];

//创建过渡对象

CATransition * transition = [CATransition animation];

transition.startProgress = 0;

transition.endProgress = 1.0;

transition.filter = aFilter;

transition.duration = 1.0;

[self.imageView2 setHidden:NO];

[self.imageView.layer addAnimation:transition forKey:@“ transition”];

[self.imageView2.layer addAnimation:transition forKey:@“ transition”];

[self.imageView setHidden:YES];

注意: 在动画中使用“核心图像”滤镜时,最棘手的部分是配置滤镜。例如,使用小节滑动过渡,将输入角度指定为太大或太小可能会使好像没有过渡发生。如果没有看到预期的动画,请尝试将滤镜参数调整为其他值,以查看是否会改变结果。

自定义动画的时间

定时是动画的重要组成部分,使用Core Animation可以通过CAMediaTiming协议的方法和属性为动画指定精确的定时信息。两个核心动画类采用此协议。CAAnimation类采用它,这样你可以指定你的动画对象的时间信息。CALayer还采用它,这样你可以配置你的隐式动画一些时间相关的功能,但它包装这些动画的隐性交易对象通常提供优先默认时序信息。

在考虑定时和动画时,重要的是了解图层对象如何随时间工作。每个图层都有自己的本地时间,用于管理动画时间。通常,两个不同层的本地时间足够接近,您可以为每个层指定相同的时间值,并且用户可能不会注意到任何事情。但是,层的本地时间可以通过其父层或自己的时序参数进行修改。例如,更改图层的speed属性会导致该图层(及其子图层)上的动画持续时间成比例地变化。

为了帮助您确保时间值适合给定的图层,CALayer该类定义convertTime:fromLayer:convertTime:toLayer:方法。您可以使用这些方法将固定时间值转换为图层的本地时间,或将时间值从一层转换为另一层。这些方法考虑了可能影响该图层本地时间的媒体计时属性,并返回了可与其他图层一起使用的值。清单5-3给出了一个示例,您应该定期使用该示例来获取图层的当前本地时间。该CACurrentMediaTime函数是一种便捷函数,它返回计算机的当前时钟时间,该方法将采用该时间并将其转换为图层的本地时间。

清单5-3 获取图层的当前本地时间

CFTimeInterval localLayerTime = [myLayer convertTime:CACurrentMediaTime()fromLayer:nil];

在图层的本地时间中有了时间值后,就可以使用该值来更新动画对象或图层的与时间相关的属性。使用这些计时属性,您可以实现一些有趣的动画行为,包括:

使用该beginTime属性设置动画的开始时间。通常,动画在下一个更新周期开始。您可以使用该beginTime参数将动画开始时间延迟几秒钟。将两个动画链接在一起的方法是设置一个动画的开始时间以匹配另一个动画的结束时间。

如果延迟动画的开始,则可能还需要将该fillMode属性设置为kCAFillModeBackwards。即使图层树中的图层对象包含其他值,此填充模式也会使图层显示动画的起始值。如果没有这种填充模式,您将看到动画开始执行之前跳到最终值的情况。其他填充模式也可用。

autoreverses属性使动画在指定的持续时间内执行,然后返回到动画的起始值。您可以将此属性与该repeatCount属性结合使用,以在开始值和结束值之间来回动画。将自动反转动画的重复计数设置为整​​数(例如1.0)会导致动画停止在其初始值上。添加额外的半步(例如1.5的重复计数)会使动画停止在其最终值上。

将该timeOffset属性与组动画一起使用,可以在比其他动画晚的时间开始一些动画。

暂停和恢复动画

要暂停动画,可以利用图层采用CAMediaTiming协议并将图层动画的速度设置为的事实0.0。将速度设置为零会暂停动画,直到将值更改回非零值为止。清单5-4给出了一个简单的示例,说明如何稍后暂停和恢复动画。

清单5-4 暂停和恢复图层的动画

-(void)pauseLayer:(CALayer *)layer {

  CFTimeInterval pausedTime = [layerLayerTime:CACurrentMediaTime()fromLayer:nil];

  layer.speed = 0.0;

  layer.timeOffset = pausedTime;

}

-(void)resumeLayer:(CALayer *)layer {

  CFTimeInterval pausedTime = [layer timeOffset];

  layer.speed = 1.0;

  layer.timeOffset = 0.0;

  layer.beginTime = 0.0;

  CFTimeInterval timeSincePause = [layerLayerTime:CACurrentMediaTime()fromLayer:nil]-pausedTime;

  layer.beginTime = timeSincePause;

}

显式事务可让您更改动画参数

您对图层所做的每次更改都必须是事务的一部分。本CATransaction类管理动画的创作和分组,并在适当的时候它们的执行。在大多数情况下,您无需创建自己的交易。每当您向图层之一添加显式或隐式动画时,Core Animation都会自动创建一个隐式事务。但是,您也可以创建显式事务来更精确地管理这些动画。

您可以使用CATransaction类的方法创建和管理交易。要启动(并隐式创建)新事务,请调用beginclass方法;要结束该事务,请调用commitclass方法。在这些调用之间是要包含在事务中的更改。例如,要更改图层的两个属性,可以使用清单5-5中的代码。

清单5-5 创建一个显式事务

[CATransaction start];

theLayer.zPosition = 200.0;

theLayer.opacity = 0.0;

[CATransaction commit];

使用事务的主要原因之一是,在显式事务的范围内,您可以更改持续时间,计时功能和其他参数。您还可以为整个事务分配完成块,以便在动画组结束时可以通知您的应用。更改动画参数需要使用setValue:forKey:方法修改交易字典中的适当键。例如,要将默认持续时间更改为10秒,您可以更改kCATransactionAnimationDuration密钥,如清单5-6所示。

清单5-6 更改动画的默认持续时间

[CATransaction start];

[CATransaction setValue:[NSNumber numberWithFloat:10.0f]

                forKey:kCATransactionAnimationDuration];

//执行动画

[CATransaction commit];

您可以在要为不同的动画集提供不同的默认值的情况下嵌套事务。要将一个事务嵌套在另一个事务中,只需begin再次调用class方法。每个begin调用必须与对该commit方法的相应调用匹配。只有在提交了最外部事务的更改之后,Core Animation才开始关联的动画。

清单5-7显示了一个嵌套在另一个事务中的示例。在此示例中,内部事务更改与外部事务相同的动画参数,但使用不同的值。

清单5-7 嵌套显式事务

[CATransaction start];//外部交易

//将动画持续时间更改为两秒

[CATransaction setValue:[NSNumber numberWithFloat:2.0f]

                forKey:kCATransactionAnimationDuration];

//将图层移动到新位置

theLayer.position = CGPointMake(0.0,0.0);

[CATransaction start];//内部交易

//将动画持续时间更改为五秒

[CATransaction setValue:[NSNumber numberWithFloat:5.0f]

                forKey:kCATransactionAnimationDuration];

//更改zPosition和不透明度

theLayer.zPosition = 200.0;

theLayer.opacity = 0.0;

[CATransaction commit]; //内部交易

[CATransaction commit]; //外部交易

为动画添加透视图

应用程序可以在三个空间维度上操纵图层,但为简单起见,Core Animation使用平行投影来显示图层,该投影实际上将场景展平为二维平面。此默认行为会导致具有相同zPosition值的大小相同的图层显示为相同的大小,即使它们在z轴上相距很远也是如此。您通常可以从三个维度查看这种场景的透视图已经消失了。但是,可以通过修改图层的转换矩阵以包括透视图信息来更改该行为。

修改场景的透视图时,需要修改sublayerTransform包含正在查看的图层的超层矩阵。通过对所有子层应用相同的透视图信息,修改超级层可简化您必须编写的代码。它还确保将透视图正确地应用于在不同平面中彼此重叠的同级子层。

清单5-8显示了为父层创建简单的透视变换的方法。在这种情况下,自定义eyePosition变量指定沿z轴查看图层的相对距离。通常,您可以为正值指定eyePosition以使层以预期方式定向。较大的值会导致场景更平坦,而较小的值会导致图层之间更明显的视觉差异。

清单5-8 将透视变换添加到父层

CATransform3D perspective = CATransform3DIdentity;

perspective.m34 = -1.0/eyePosition;

// Apply the transform to a parent layer.

myParentLayer.sublayerTransform = perspective;

配置了父层后,您可以更改zPosition任何子层的属性,并根据它们与眼睛位置的相对距离来观察其大小如何变化。

相关文章

网友评论

      本文标题:iOS中高级动画技巧

      本文链接:https://www.haomeiwen.com/subject/spdgnctx.html