Core Animation Programming Guide - Advanced Animation Tricks

Advanced Animation Tricks

有许多方式能够配置你的 property-based 或 keyframe 动画,这些方式能够为你作不少。若想让 App 同时或者按顺序表现多个动画,你可使用更多高级的行为来同步这些动画的时间或者动画的链条。你也可使用其余动画类型对象建立视觉过分和其余有意思的动画效果。缓存


Transition Animations Support Changes to Layer Visibility

就像名字同样,一个过分动画对象为一个 layer 建立一个动画的视觉过分。最日常的过分对象使用是在一个坐标行为中一个 layer 的显现和另外一个 layer 的消失。不像 property-based 动画,在动画改变 layer 的属性的地方,一个过分动画操纵一个 layer 的缓存图像以建立视觉效果,单靠改变属性是很困难或者不可能的。标准的过分类型使你表现重现、推、移动或者淡入淡出动画。在 OS X 中,你也可使用 Core Image 滤镜建立过分,使用其余影响类型,好比扫、翻页、波纹、或者你设计的自定义效果。app

为了建立一个过分动画,你要建立一个 CATransition 对象,并且要把它添加到过分中包括的 layer。你使用过分对象明确过分类型,表现、开始和结束过分动画的点。你不须要使用整个的过分动画。当动画时,过分对象使你明确起始进度值的使用。这些值使你在动画的中点作一些事情,好比开始或结束这个动画。动画

代码 5-1 展现了在两个视图之间建立一个 push 过渡动画的代码。在这个例子中,myView1 和 myView2 位于同一个父层视图中,位置都是相同的,只是 myView1 是当前可见的视图。push 过渡动画致使 myView1 向左淡出直至消失,同时 myView2 从右边淡入成为当前可见视图。在动画结束的时候更新两个 hidden 属性,以便这两个视图正确显现。设计

代码 5-1 Animating a transition between two views in iOScode

CATransition *transition = [CATransition animation];

transition.startProgress = 0;

transition.endProgress = 0;

transition.type = kCATransitionPush;

transition.subtype = kCATransitionFromRight;

transition.duration = 1.0;


// Add the transition animation to both layers

[myView1.layer addAnimation:transition forKey:@"transition"];

[myView2.layer addAnimation:transition forKey:@"transition"];


// Finally, change the visibility of the layers

myView1.hidden = YES;

myView2.hidden = NO;

当两个 layer 被包括进同一个过渡中,你能够为他们使用同一个过渡对象。使用同一个过渡对象简化了代码。然而,当每一个 layer 的过渡的参数不一样时,就须要使用多个过渡对象了。orm

代码 5-2 展现了在 OS X 上怎么使用 Core Image 滤镜实现过渡效果。用你想要的参数配置完滤镜后,把它赋给过渡对象的 filter 属性。以后的动画应用过程和其余动画对象的类型相同。对象

代码 5-2 Using a Core Image filter to animate a transition on OS X事务

// Create the Core Image filter, setting several key parameters.

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"];


// Create the transition object

CATransition *transition = [CATranstion 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 Image 滤镜时,最困难的部分是配置滤镜。例如,使用 bar swipe 过渡,肯定一个 input angle 过高或者过低均可能会形成它看起来没有发生过渡。若是你没有看到指望的动画,尝试着调整滤镜的参数,查看参数值的变化十分产生变化的结果。ip


Customizing the Timing of an Animation

时间是动画中很重要的部分,经过 Core Animation 协议 CAMediaTiming 的方法和属性指明动画的时间精度信息。有两个 Core Animation 类使用这个协议。CAAnimation使用它,你能够经过这个类的实例指定时间信息。CALayer 也使用这个协议,尽管隐性的动画一般具备优先默认的时间信息,你也可使用一些相关的时间属性配置它。ci

当考虑动画和时间时,理解 layer 对象怎么用时间工做很重要。每个 layer 都有它本身用来管理动画计时的本地时间。通常两个不一样的 layer 的本地时间是很接近的,你能够为他们使用同一个时间值而用户可能不会注意到。可是本地时间能够被它的父层 layer 或者自身的计时参数修改。好比,改变 layer 的 speed 属性会致使自身(子层 layer)动画的持续时间相应地变化。

为了协助你为给定的 CALayer 肯定合适的时间值,CALayer 类定义了 convertTime:fromeLayer: 和 convertTime:toLayer: 方法。你能够用这些方法转换一个固定的时间值为 layer 的本地时间或者把一个 layer 的时间值转换为另外一个的。这两个方法考虑了可能影响 layer 本地时间的媒体时间属性,并且返回一个你能够在其余 layer 使用的值。代码 5-3 展现了常规下得到一个 layer 的当前本地时间。CACurrentMediaTime 方法是一个很方便的方法,返回当前电脑的时钟时间,会被转换为 layer 的本地时间。

代码 5-3 Getting a layer's current local time

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

一旦你有了 layer 的本地时间值,你可使用它更新动画对象或者 layer 时间相关的属性。使用这些时间属性,你能够得到一些有趣的动画行为,包括:

  • 使用 beginTime 属性设置动画的起始时间。通常地,动画在下一个循环更新期间开始。你可使用 beginTime 参数延迟几秒动画的开始时间。把两个动画串一块儿的方式是设置一个的开始时间为另外一个的结束时间。

    若是你延迟了动画的开始,你也可能想设置 fillMode 属性为 kCAFillModeBackwards。这个填充模式致使 layer 显示动画的开始值,即便在 layer 树中的 layer 对象包含一个不一样的值。没有这个填充模式,你将在动画开始执行前看到一个跳跃的最终值。其余的填充模式也可使用。
  • autoreverses 属性致使一个动画在明确的区间执行,而后返回动画的开始值。你能够用 repeatCount 属性合并这个属性,而后动画回来,在起始值之间跳转。为一个自动转变的动画设置重复记数为整数值(好比 1.0)会致使动画在开始值上中止。添加额外半步(好比 1.5)会致使动画在它的结束值中止。
  • 用组动画使用 timeOffset 属性比其余的动画要开始的晚一点。

Pausing and Resuming Animations

你能够利用 layer 实现 CAMediaTiming 协议,而后设置 layer 的动画速度为 0.0,会使动画暂停。设置速度为 0 会暂停动画直至你变为非零值。代码 5-4 展现了一个如何暂停和恢复动画的简单例子。

代码 5-4 Pausing and resuming a layer's animations

-(void)pauseLayer:(CALayer*)layer{
    CFTimeInterval pausedTime = [layer convertTime: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 = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
    
    layer.beginTime = timeSincePause;
}

Explicit Transaction Let You Change Animation Parameters

你作的每个改变必须是事务的一部分。CATransaction 类管理动画的建立和聚合,还有动画在合适时间的执行。多数状况下,你不须要建立本身的事务。不管你在何时为 layer 添加隐性或显性动画, Core Animation 自动地建立了一个隐性事务。可是你也能够建立本身的事务,更大粒度的管理这些动画。

你用 CATransaction 类的方法建立和管理事务。调用类方法 begin 开始(隐性建立)一个新的事务;调用类方法 commit 结束事务。在这两个方法调用中间是你想作的事务部分的改变。例如,改变 layer 的两个属性,你可使用代码 5-5 中的代码。

代码 5-5 Creating an explicit transaction

[CATransaction begin];

theLayer.zPosition = 200.0;

theLayer.opacity = 0.0;

[CATransaction commit];

使用事务的最主要缘由之一是由于在一个显式的事务限制以内,你能够改变持续时间,时间方法和其余的参数。你也能够赋给整个事务一个完整的 block,以便你的 app 在一组动画完成时收到通知。改变更画参数须要使用 setValue:forKey: 方法修改事务字典的合适键。例如,更改默认持续时间到 10 秒,你将改变 kCATransactionAnimationDuration 键,如代码 5-6

代码 5-6 Changing the default duration of animaitons

[CATransaction begin];

[CATransaction setValue:[NSNumber numberWithFloat:10.0f] forKey:kCATransactionAnimationDuration];

// Perform the animations

[CATransaction commit];

你能够在想为不一样的动画集提供不一样的默认值时叠加事务。把一个事务叠加到另外一个中,只须要再一次调用类方法 begin。每一次 begin 的调用必须有一个相对应的 commit 方法调用。只有你为最外面的事务提交了变动 Core Animation 才开始相关的动画。

代码 5-7 展现了一个嵌套的事务。在这个例子中,内层的事务像外层同样改变了同一个动画的参数,可是使用了不一样的值。

代码 5-7 Nesting explicit transactions

[CATransaction begin]; // Outer transaction


// Change the animation duration to two seconds

[CATransaction setValue:[NSNumber numberWithFloat:2.0f] forKey:kCATransactionAnimationDuration];

// Move the layer to a new position

theLayer.position = CGPointMake(0.0, 0.0);



[CATransaction begin]; // Inner transaction

// Change the animation duration to five seconds

[CATransaction setValue:[NSNumber numberWithFloat:5.0f] forKey:kCATransactionAnimationDuration];


// Change the zPosition and opacity

theLayer.zPosition = 200.0;

theLayer.opacity = 0.0;


[CATransaction commit]; // Inner transaction


[CATransaction commit]; // Outer transaction

Adding Perspective to Your Animations

App 能够在三维空间中操做 layer,可是为了简单 Core Animation 使用一个平行项目显示 layer,这个项目把场景平植到一个二维平面中。这个默认的行为致使相同尺寸不一样 zPosition 值的 layer 以同一个尺寸展示,即便他们在 z 轴上相差很远。通常状况下你看到的三维场景透视就不存在啦。可是,你能够修改 layer 的 transformation matrix 包含透视信息来改变这个行为。

当修改场景的透视时,你须要修改包含了被看到的视图的父层 layer 的 sublayerTransform 矩阵。修改父层 layer 简化了你不得不写的应用到全部子层的透视信息的代码。它还确保了透视能被正确的应用到在不一样平面上重叠的兄弟层 layr。

代码 5-8 展现了建立一个父层 layer 的简单透视 transform 代码。在这里自定义的 eyePosition 变量指明了沿着 z 轴到视图的相对距离。通常你为 eyePosition 指定一个正数,以便保持 layer 的水平。在一个平面视图中会有更大的值,而更小的值会致使不一样的 layer 之间产生戏剧性的视觉效果。

代码 5-8 Adding a perspective transform to a parent layer

CATransform3D perspective = CATransform3DIdentity;

perspective.m34 = -1.0/eyePosition;


// Apply the transform to a parent layer.

myParentLayer.sublayerTransform = perspective;

使用父层 layer 的配置,你能够改变任意子层 layer 的 zPosition 属性,并且还能够观察它们的尺寸是如何基于它们的相对距离从视觉位置改变的。

相关文章
相关标签/搜索