Animations

Animations provide fluid visual transitions between different states of your user interface. In iOS, animations are used extensively to reposition views, change their size, remove them from view hierarchies, and hide them. You might use animations to convey feedback to the user or to implement interesting visual effects.

动画提供流畅的视觉过渡,用来表示用户界面的不同状态之间的转换。 在iOS里,动画被广泛用于重定位视图,改变它们的尺寸,把它们从视图层次结构中删除,以及隐藏它们。你可以用动画来给用户传递反馈或实现有趣的视觉效果。

In iOS, creating sophisticated animations does not require you to write any drawing code. All of the animation techniques described in this chapter use the built-in support provided by Core Animation. All you have to do is trigger the animation and let Core Animation handle the rendering of individual frames. This makes creating sophisticated animations very easy with only a few lines of code.

在iOS中,创建复杂的动画并不要求你编写任何绘制代码。 所有本章描述的动画技术都由内核动画(Core Animation)内置提供。 所有你要做的是促发动画并让内核动画处理单个帧的渲染。 这使得创建复杂动画很简单,只需要很少几行代码。

What Can Be Animated?

一、哪些能被动画?

Both UIKit and Core Animation provide support for animations, but the level of support provided by each technology varies. In UIKit, animations are performed using UIView objects. Views support a basic set of animations that cover many common tasks. For example, you can animate changes to properties of views or use transition animations to replace one set of views with another.

UIKit和Core Animation都提供了对动画的支持,但是每种技术所支持的等级并不同。 在UIKit中,动画由UIView对象执行。 视图支持动画的一个基本集合,它覆盖了一些通用任务。比如,你可以用动画更改视图属性或使用过渡动画来把一个视图集替换为另一个视图集。

Table 4-1 lists the animatable properties—the properties that have built-in animation support—of the UIView class. Being animatable does not mean animations happen automatically. Changing the value of these properties normally just updates the property (and the view) immediately without an animation. To animate such a change, you must change the property’s value from inside an animation block, which is described in “Animating Property Changes in a View.”

表格4-1 列出了UIView类中可动画的各种属性---已经内置动画支持的各种属性。能够动画化并不意味着动画会自动发生。 改变这些属性通常只要立即更新该属性(以及视图)不需要动画。 要想动画这样一个改变,你必须从一个动画块内部改变属性的值,这在“Animating Property Changes in a View.” 里有详细描述。

Table 4-1  Animatable UIView properties表 4-1 可动画UIView属性

Property

Changes you can make

你可以做的修改

frame

Modify this property to change the view’s size and position relative to its superview’s coordinate system. (If the transform property does not contain the identity transform, modify the bounds or center properties instead.)

修改该属性来改变视图的尺寸和在它父视图坐标系统里的位置。(如果transform 属性没有包含恒等变换--identity transform--, 用修改bounds 或 center属性替代)

bounds

Modify this property to change the view’s size.

修改该属性来改变视图的尺寸。

center

Modify this property to change the view’s position relative to its superview’s coordinate system.

修改该属性来改变视图位于其父视图坐标系统中的位置。

transform

Modify this property to scale, rotate, or translate the view relative to its center point. Transformations using this property are always performed in 2D space. (To perform 3D transformations, you must animate the view’s layer object using Core Animation.)

修改该属性来缩放,旋转,或做围绕它中心点的变化。 使用该属性的变换永远执行在2D空间。(要想执行3D变换,你必须使用Core Animation来动画视图的层对象。)

alpha

Modify this property to gradually change the transparency of the view.

修改该属性来逐渐改变视图的透明度。

backgroundColor

Modify this property to change the view’s background color.

修改该属性来改变视图的背景颜色。

contentStretch

Modify this property to change the way the view’s contents are stretched to fill the available space.

修改该属性来改变视图拉伸的方式,拉伸视图来填充视图的可用空间。

Animated view transitions are a way for you to make changes to your view hierarchy beyond those offered by view controllers. Although you should use view controllers to manage succinct view hierarchies, there may be times when you want to replace all or part of a view hierarchy. In those situations, you can use view-based transitions to animate the addition and removal of your views.

动画视图变换是一种方法,让你对不是由视图控制器提供的视图层次结构做改变。尽管你应该使用视图控制器来管理简洁的视图层次结构, 但是有些时候当你想替换层次结构的所有或部分内容时可能会使用它。在那些情况下,你可以使用基于视图的各种变换来动画视图的添加和删除操作。

In places where you want to perform more sophisticated animations, or animations not supported by the UIViewclass, you can use Core Animation and the view’s underlying layer to create the animation. Because view and layer objects are intricately linked together, changes to a view’s layer affect the view itself. Using Core Animation, you can animate the following types of changes for your view’s layer:

当你想执行更复杂的动画或执行不被UIView类支持的各种动画时,你可以使用Core Animation以及视图的后台层(underlying layer)来创建动画。 因为视图和层对象是错综复杂地被连接到一起的,所以对一个视图层的改变也将影响视图本身。 使用Core Animation , 你的视图层的以下类型改变可以被动画:

  • The size and position of the layer

    层的尺寸和位置

  • The center point used when performing transformations

    执行各种变换时使用的中心点

  • Transformations to the layer or its sublayers in 3D space

    在3D空间里对层或其子层所做的各种变换

  • The addition or removal of a layer from the layer hierarchy

    在层层次结构中添加或删除一个层 

  • The layer’s Z-order relative to other sibling layers

    层相对于其它兄弟姐妹层的Z 顺序

  • The layer’s shadow

     层的阴影

  • The layer’s border (including whether the layer’s corners are rounded)

     层边框(包括层的角是否是圆角)

  • The portion of the layer that stretches during resizing operations

    层在重新调整尺寸操作过程中延伸的部分

  • The layer’s opacity

     层的透明度

  • The clipping behavior for sublayers that lie outside the layer’s bounds

     子层(超出层的边界)的剪切行为

  • The current contents of the layer

     层的当前内容

  • The rasterization behavior of the layer

     层的栅格化行为

Note: If your view hosts custom layer objects—that is, layer objects without an associated view—you must use Core Animation to animate any changes to them.

注意: 如果你的视图承载了自定义层对象---就是说,没有相关联视图的层对象---你必须使用Core Animation 来动画它们的任何改变。

Although this chapter addresses a few Core Animation behaviors, it does so in relation to initiating them from your view code. For more complete information about how to use Core Animation to animate layers, see Core Animation Programming Guide and Core Animation Cookbook.

尽管本章讲演了一些Core Animation 行为,但是它是通过在你的视图代码中初始化它们来实现的。关于如何使用Core Animaiton 来动画层的完整信息,请看 Core Animation Programming Guide 和  Core Animation Cookbook.

Animating Property Changes in a View

二、在一个视图里动画属性的改变

In order to animate changes to a property of the UIView class, you must wrap those changes inside an animation block. The term animation block is used in the generic sense to refer to any code that designates animatable changes. In iOS 4 and later, you create an animation block using block objects. In earlier versions of iOS, you mark the beginning and end of an animation block using special class methods of the UIView class. Both techniques support the same configuration options and offer the same amount of control over the animation execution. However, the block-based methods are preferred whenever possible.

为了动画UIView 类中属性的各种改变,你必须在一个动画块里包装这些改变。 一般意义上来说,动画块是指指定可动画改变的任何代码。在iOS4以及之后的版本中,你可以使用块对象来创建一个动画块。 在iOS的早期版本中,你使用UIView类的特殊类方法来标记一个动画块的起始与结束。两项技术都支持同样的配置选项,并提供动画执行相同数量的控制。然而,只要可能基于块的方法是优选。

The following sections focus on the code you need in order to animate changes to view properties. For information about how to create animated transitions between sets of views, see “Creating Animated Transitions Between Views.”

以下段主要专注于你需要的代码,用来动画视图属性的各种改变。 关于如何在视图集之间创建动画过渡的信息,请看“Creating Animated Transitions Between Views.”

Starting Animations Using the Block-Based Methods

1、使用基于块的方法来启动动画

In iOS 4 and later, you use the block-based class methods to initiate animations. There are several block-based methods that offer different levels of configuration for the animation block. These methods are:

在iOS4以及之后的版本中,你可以使用基于块的类方法来初始化各种动画。下面有一些基于块的方法,用来为动画块提供不同层次的配置:

Because these are class methods, the animation blocks you create with them are not tied to a single view. Thus, you can use these methods to create a single animation that involves changes to multiple views. For example, Listing 4-1shows the code needed to fade in one view while fading out another over a one second time period. When this code executes, the specified animations are started immediately on another thread so as to avoid blocking the current thread or your application’s main thread.

因为这些都是类方法,所以你用它们创建出来的动画块不跟单个视图绑定。 因此,你可以使用这些方法来创建设计多个视图改变的单个动画。比如,列表4-1显示了一些代码,代码实现在一秒内从一个视图内淡出,再淡入另一个视图。当该代码被执行时,指定动画立即在其它线程里启动以免阻塞当前线程或应用程序的主线程。

Listing 4-1  Performing a simple block-based animation

列表 4-1 执行一个简单的基于块的动画

[UIView animateWithDuration:1.0 animations:^{
        firstView.alpha = 0.0;
        secondView.alpha = 1.0;
}];

The animations in the preceding example run only once using using an ease-in, ease-out animation curve. If you want to change the default animation parameters, you must use theanimateWithDuration:delay:options:animations:completion: method to perform your animations. This method lets you customize the following animation parameters:

上例中的动画使用一个淡入,淡出动画曲线,它只被执行一次。如果你想要改变默认动画参数,你必须使用animateWithDuration:delay:options:animations:completion: 方法来执行你的动画。该方法让你自定义以下动画参数:

  • The delay to use before starting the animation

    启动动画前的延迟时间

  • The type of timing curve to use during the animation

    在动画期间使用的时间曲线类型

  • The number of times the animation should repeat

    动画重复的次数

  • Whether the animation should reverse itself automatically when it reaches the end

    动画结束时是否自动反转(reverse)

  • Whether touch events are delivered to views while the animations are in progress

    动画进行时是否把触摸时间传递给视图

  • Whether the animation should interrupt any in-progress animations or wait until those are complete before starting

    动画是否应该中断任何正在进行的动画,或者等到这些都完成后才启动

Another thing that both the animateWithDuration:animations:completion: andanimateWithDuration:delay:options:animations:completion: methods support is the ability to specify a completion handler block. You might use a completion handler to signal your application that a specific animation has finished. Completion handlers are also the way to link separate animations together.

animateWithDuration:animations:completion: 和 

animateWithDuration:delay:options:animations:completion: 方法都有指定一个结束处理程序块的能力。 你可以使用一个结束处理程序来通知应用程序一个特定动画已经结束。结束处理程序也同样是连接分离动画的一种方法。

Listing 4-2 shows an example of an animation block that uses a completion handler to initiate a new animation after the first one finishes. The first call to animateWithDuration:delay:options:animations:completion: sets up a fade-out animation and configures it with some custom options. When that animation is complete, its completion handler runs and sets up the second half of the animation, which fades the view back in after a delay.

列表 4-2 显示了一个例子,该例子实现了一个使用了一个结束处理程序的动画块在第一个动画结束后初始化一个新动画。第一次调用animateWithDuration:delay:options:animations:completion:建立看一个淡出动画并配置了一个自定义选项。 当那个动画结束时,它的结束处理程序启动并建立了半个第二个动画,该动画在一定延迟之后把视图重新淡入。

Using a completion handler is the primary way that you link multiple animations.

使用一个结束处理程序是连接多个动画的主要方法。

Listing 4-2  Creating an animation block with custom options

列表 4-2 用自定义选项创建一个动画块

- (IBAction)showHideView:(id)sender
{
    // Fade out the view right away
    [UIView animateWithDuration:1.0
        delay: 0.0
        options: UIViewAnimationOptionCurveEaseIn
        animations:^{
             thirdView.alpha = 0.0;
        }
        completion:^(BOOL finished){
            // Wait one second and then fade in the view
            [UIView animateWithDuration:1.0
                 delay: 1.0
                 options:UIViewAnimationOptionCurveEaseOut
                 animations:^{
                    thirdView.alpha = 1.0;
                 }
                 completion:nil];
        }];
}

Important: Changing the value of a property while an animation involving that property is already in progress does not stop the current animation. Instead, the current animation continues and animates to the new value you just assigned to the property.

重要提示:当动画涉及的属性已经在处理中时,改变该属性的值并不会停止当前动画。它会继续当前动画并把动画到你刚分配给属性的新值。

Starting Animations Using the Begin/Commit Methods

2、 使用Begin/Commit 方法来启动动画

If your application runs in iOS 3.2 and earlier, you must use the beginAnimations:context: andcommitAnimations class methods of UIView to define your animation blocks. These methods mark the beginning and end of your animation block. Any animatable properties you change between these methods are animated to their new values after you call the commitAnimations method. Execution of the animations occurs on a secondary thread so as to avoid blocking the current thread or your application’s main thread.

如果你的应用程序运行在iOS3.2 以及之前版本,你必须使用UIView类的beginAnimations:context: 和 commitAnimations类方法来定义你的动画块。这些方法标记动画块的起始和结束。你通过这些方法实现的任何可动画属性都在你调用commitAnimations方法之后动画它们的新值。动画发生的执行过程在辅助线程里执行,以避免阻塞当前线程或应用程序的主线程。

Note: If you are writing an application for iOS 4 or later, you should use the block-based methods for animating your content instead. For information on how to use those methods, see “Starting Animations Using the Block-Based Methods.”

 注意:如果你为iOS4或以后版本编写一个应用程序,你应该使用基于块的方法来动画你的内容。 关于如何使用这些方法的信息,请看“Starting Animations Using the Block-Based Methods.”

Listing 4-3 shows the code needed to implement the same behavior as Listing 4-1 but using the begin/commit methods. As in Listing 4-1, this code fades one view out while fading another in over one second of time. However, in this example, you must set the duration of the animation using a separate method call.

列表4-3 显示了使用begin/commit方法来实现跟列表4-1(Listing 4-1)相同行为所需要的代码。正如列表4-1,该代码实现1秒内从一个视图淡出,然后在另一视图里淡入。然而,该例子你必须使用一个单独的方法调用来设置动画的运行时间。

Listing 4-3  Performing a simple begin/commit animation

列表 4-3 执行一个简单的begin/commit动画

    [UIView beginAnimations:@"ToggleViews" context:nil];
    [UIView setAnimationDuration:1.0];
 
    // Make the animatable changes.
    firstView.alpha = 0.0;
    secondView.alpha = 1.0;
 
    // Commit the changes and perform the animation.
    [UIView commitAnimations];

By default, all animatable property changes within an animation block are animated. If you want to animate some changes but not others, use the setAnimationsEnabled: method to disable animations temporarily, make any changes that you do not want animated, and then call setAnimationsEnabled: again to reenable animations. You can determine if animations are current enabled by calling the areAnimationsEnabled class method.

默认时,在一个动画块里的所有可动画属性个改变都被动画。如果你想要动画一些但不是全部改变,使用setAnimationsEnabled: 方法暂时无效一些动画,对你不想动画的属性做改变,然后再次调用setAnimationsEnabled:方法让那些动画重新启用。 你可以通过调用areAnimationsEnabled 方法来查看动画目前是否已经被启用。

Note: Changing the value of a property while an animation involving that property is in progress does not stop the current animation. Instead, the animation continues and animates to the new value you just assigned to the property.

 注意:当动画涉及的属性已经在处理中时,改变该属性的值并不会停止当前动画。它会继续当前动画并把动画到你刚分配给属性的新值。

Configuring the Parameters for Begin/Commit Animations

3、 为Begin/Commit动画配置参数

To configure the animation parameters for a begin/commit animation block, you use any of several UIViewclass methodsTable 4-2 lists these methods and describes how you use them to configure your animations. Most of these methods should be called only from inside a begin/commit animation block but some may also be used with block-based animations. If you do not call one of these methods from your animation block, a default value for the corresponding attribute is used. For more information about the default value associated with each method, see the method description in UIView Class Reference.

要想为一个begin/commit动画块配置动画参数,你可以使用一些UIView 类方法的任何一个。 表4-2 列出了这些方法并描述了如何使用它们来配置你的动画。 这些方法的大多数方法都应该值从一个begin/commit动画块内容调用,但是一些方法可能也可以被用于基于块的动画中。 如果你不从你的动画块中调用这些方法,相关属性的一个默认值将被采用。关于每个方法的相关默认值的更多信息,请看UIView Class Reference 中的方法描述。

Table 4-2  Methods for configuring animation blocks表 4-2 配置动画块的各种方法

Method

Usage

setAnimationStartDate:

setAnimationDelay:

Use either of these methods to specify when the executions should begin executing. If the specified start date is in the past (or the delay is 0), the animations begin as soon as possible.

使用任何一个方法来指定何时应该开始执行操作。如果指定的启动日期已经过去(或延迟为0),动画将尽可能快的开始。

setAnimationDuration:

Use this method to set the period of time over which to execute the animations.

使用该方法来设置动画执行的时间。

setAnimationCurve:

Use this method to set the timing curve of the animations. This controls whether animations execute linearly or change speed at certain times.

使用该方法来设置动画的时间曲线(timing curve)。 该值控制动画是被线性执行还是在特定时候改变速度。

setAnimationRepeatCount:

setAnimationRepeatAutoreverses:

Use these methods to set the number of times the animation repeats and whether the animation runs in reverse at the end of each complete cycle. For more information about using these methods, see “Implementing Animations That Reverse Themselves.”

使用这些方法来设置动画重复的次数,以及该动画是否在每个完整周期结束时翻转自己。关于使用这些方法的更多信息,请看“Implementing Animations That Reverse Themselves.”

setAnimationDelegate:

setAnimationWillStartSelector:

setAnimationDidStopSelector:

Use these methods to execute code immediately before or after the animations. For more information about using a delegate, see“Configuring an Animation Delegate.”

使用这些方法在动画之前或之后立即执行代码。关于使用一个委托的更多信息,请看“Configuring an Animation Delegate.”

setAnimationBeginsFromCurrentState:

Use this method to stop all previous animations immediately and start the new animations from the stopping point. If you pass NO to this method, instead of YES, the new animations do not begin executing until the previous animations stop.

使用该方法来立即停止所有先前的动画并在停止点启动各种新的动画。如果你给该方法传递NO,而不是YES, 新动画直到以前的动画停止后才开始执行。

Listing 4-4 shows the code needed to implement the same behavior as the code in Listing 4-2 but using the begin/commit methods. As before, this code fades out a view, waits one second, and then fades it back in. In order to implement the second part of the animation, the code sets up an animation delegate and implements a did-stop handler method. That handler method then sets up the second half of the animations and runs them.

列表 4-4 显示了实现Listing 4-2 相同行为所需的代码,该例子使用了begin/commit方法。 正如之前所示,该代码淡出一个视图,等待一秒钟,然后重新把它淡入。 为了实现第二部分的动画,代码建立一个动画委托并实现一个did-stop处理程序方法。那个处理程序方法然后建立半个第二个动画,并运行它们。

Listing 4-4  Configuring animation parameters using the begin/commit methods

列表4-4 使用begin/commit方法来配置动画参数

// This method begins the first animation.
- (IBAction)showHideView:(id)sender
{
    [UIView beginAnimations:@"ShowHideView" context:nil];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
    [UIView setAnimationDuration:1.0];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(showHideDidStop:finished:context:)];
 
    // Make the animatable changes.
    thirdView.alpha = 0.0;
 
    // Commit the changes and perform the animation.
    [UIView commitAnimations];
}
 
// Called at the end of the preceding animation.
- (void)showHideDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{
    [UIView beginAnimations:@"ShowHideView2" context:nil];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
    [UIView setAnimationDuration:1.0];
    [UIView setAnimationDelay:1.0];
 
    thirdView.alpha = 1.0;
 
    [UIView commitAnimations];
}

Configuring an Animation Delegate

4、配置一个动画委托

If you want to execute code immediately before or after an animation, you must associate a delegate object and a start or stop selector with your begin/commit animation block. You set your delegate object using thesetAnimationDelegate: class method of UIView and you set your start and stop selectors using thesetAnimationWillStartSelector: and setAnimationDidStopSelector: class methods. During the animation, the animation system calls your delegate methods at the appropriate times to give you a chance to perform your code.

如果你想要在一个动画之前或之后立即执行代码,你必须关联一个委托对象以及一个带有begin/commit动画块的启动或停止selector。你使用UIView类的setAnimationDelegate: 来设置你的委托对象, 使用setAnimationWillStartSelector: 和 setAnimationDidStopSelector: 类方法来设置你的启动和停止selectors。 在动画期间,动画系统在适当的时候调用你的委托方法来执行你的代码。

The signatures of your animation delegate methods need to be similar to the following:

动画委托方法的签名应该类似以下代码:

- (void)animationWillStart:(NSString *)animationID context:(void *)context;
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context;

The animationID and context parameters for both methods are the same parameters that you passed to thebeginAnimations:context: method at the beginning of the animation block:

两个方法中的animationID context 参数跟你在动画块开始处传给beginAnimations:context:方法的参数一样。

  • animationID—An application-supplied string used to identify the animation.

    animationID-- 一个用来识别动画的由应用程序提供的字符串。

  • context—An application-supplied object that you can use to pass additional information to the delegate.

    context-- 用来给委托传递额外信息的由应用程序提供的一个对象。

The setAnimationDidStopSelector: selector method has an additional parameter—a Boolean value that is YES if the animation ran to completion. If the value of this parameter is NO, the animation was either canceled or stopped prematurely by another animation.

setAnimationDidStopSelector: selector 方法有一个额外的参数---一个布尔值,如果动画已经结束,该值为YES。如果该参数的值为NO, 动画则过早地已经被其它动画取消或停止。

Note: Although animation delegates can be used in the block-based methods, there is generally no need to use them there. Instead, place any code you want to run before the animations at the beginning of your block and place any code you want to run after the animations finish in a completion handler.

 注意:尽管动画委托能被用于基于块的方法,但是基本上不需要在那里使用它们。你可以在块开始处放置任何你想要在动画前执行的代码,在一个结束处理程序中动画结束后放置任何你想要运行的代码。

Nesting Animation Blocks

5、嵌套动画块

You can assign different timing and configuration options to parts of an animation block by nesting additional animation blocks. As the name implies, a nested animation block is a new animation block created inside an existing animation block. Nested animations are started at the same time as any parent animations but run (for the most part) with their own configuration options. By default, nested animations do inherit the parent’s duration and animation curve but even those options can be overridden as needed.

 你可以通过嵌套额外的动画块给一个动画的各个部分分配不同的时间(timing)和配置选项。正如名字所指,一个嵌套动画块是在一个已经存在的动画块里创建的新的动画块。嵌套的动画跟父动画同时启动,但是(大部分)在它们自己的配置选项下运行。默认情况下,嵌套动画确实继承了父类的持续时间以及动画曲线,但是即使是那些选项也可以根据需要被重载。

Listing 4-5 shows an example of how a nested animation is used to change the timing, duration, and behavior of some animations in the overall group. In this case, two views are being faded to total transparency, but the transparency of the anotherView object is changed back and forth several times before it is finally hidden. TheUIViewAnimationOptionOverrideInheritedCurve and UIViewAnimationOptionOverrideInheritedDurationkeys used in the nested animation block allow the curve and duration values from the first animation to be modified for the second animation. If these keys were not present, the duration and curve of the outer animation block would be used instead.

列表4-5 显示了一个例子,说明一个嵌套动画在整体组中如何被用于改变时间(timing),持续时间,以及一些动画的行为。在这里,两个视图都将被减淡至完全透明,但是另一个视图对象的透明度被来来回回好几次后最终被隐藏。在嵌套动画块中使用的 UIViewAnimationOptionOverrideInheritedCurve 和
UIViewAnimationOptionOverrideInheritedDuration 关键字(keys)允许从第一个动画曲线和持续时间值修改为第二个动画配置的曲线和持续时间。如果这些关键字不存在,第二动画采用外部动画块的持续时间和曲线。

Listing 4-5  Nesting animations that have different configurations

列表 4-5 有不同配置的嵌套动画

[UIView animateWithDuration:1.0
        delay: 1.0
        options:UIViewAnimationOptionCurveEaseOut
        animations:^{
            aView.alpha = 0.0;
 
            // Create a nested animation that has a different
            // duration, timing curve, and configuration.
            [UIView animateWithDuration:0.2
                 delay:0.0
                 options: UIViewAnimationOptionOverrideInheritedCurve |
                          UIViewAnimationOptionCurveLinear |
                          UIViewAnimationOptionOverrideInheritedDuration |
                          UIViewAnimationOptionRepeat |
                          UIViewAnimationOptionAutoreverse
                 animations:^{
                      [UIView setAnimationRepeatCount:2.5];
                      anotherView.alpha = 0.0;
                 }
                 completion:nil];
 
        }
        completion:nil];

If you are using the begin/commit methods to create your animations, nesting works in much the same way as with the block-based methods. Each successive call to beginAnimations:context: within an already open animation block creates a new nested animation block that you can configure as needed. Any configuration changes you make apply to the most recently opened animation block. All animation blocks must be closed with a call tocommitAnimations before the animations are submitted and executed.

如果你使用begin/commit 方法来创建你的动画,嵌套工作跟基于块的方法基本上一样。 每次在一个已经打开的动画块里成功调用beginAnimations:context:方法,你都可以根据需要配置一个新嵌套动画块。 任何你做的配置改变影响最近期被打开的动画块。 所有动画块必须在动画被提交和执行之前调用commitAnimations 来关闭。

Implementing Animations That Reverse Themselves

6、实现反转自身的动画

When creating reversible animations in conjunction with a repeat count, consider specifying a non integer value for the repeat count. For an autoreversing animation, each complete cycle of the animation involves animating from the original value to the new value and back again. If you want your animation to end on the new value, adding 0.5 to the repeat count causes the animation to complete the extra half cycle needed to end at the new value. If you do not include this half step, your animation will animate to the original value and then snap quickly to the new value, which may not be the visual effect you want.

当你创建一个可反转动画,这只一个重复次数时,考虑指定一个非整数值作为重复次数。 对于一个自动反转动画,每个动画的完整周期涉及从初始值到新值以及再次返回的动画。 如果你想要你的动画以新值结束,给重复次数增加一个0.5,让动画完成额外半个周期让其在新值结束。如果你不包含该半个周期, 动画将被动画到初始值,然后很快速跳至新值,这样就无法达到你想要的视觉效果。

Creating Animated Transitions Between Views

三、创建视图之间的动画过渡

View transitions help you hide sudden changes associated with adding, removing, hiding, or showing views in your view hierarchy. You use view transitions to implement the following types of changes:

视图过渡帮你在视图层次结构里隐藏跟添加,删除,隐藏,或显示视图相关的各种突然改变。你可以使用视图过渡来实现以下类型的改变:

  • Change the visible subviews of an existing view. You typically choose this option when you want to make relatively small changes to an existing view.

     改变一个已经存在视图的可见子视图。 当你想对一个已经存在的视图做相对小的改变时,你通常可以选择该项。

  • Replace one view in your view hierarchy with a different view. You typically choose this option when you want to replace a view hierarchy that spans all or most of the screen.

    在你的视图层次结构里用一个不同的视图替换另一个视图。当你想替换一个跨所有或大部分屏幕的视图层次结构时,你通常可以选择该项。

Important: View transitions should not be confused with transitions initiated by view controllers, such as the presentation of modal view controllers or the pushing of new view controllers onto a navigation stack. View transitions affect the view hierarchy only, whereas view-controller transitions change the active view controller as well. Thus, for view transitions, the view controller that was active when you initiated the transition remains active when the transition finishes.

重要提示:别把视图过渡跟由视图控制器发起(initiated by)的过渡(比如模型视图控制器的呈现或把新视图控制器压入一个导航栈)相混淆。视图过渡只影响视图层次结构,而视图-控制器过渡改变活动的视图控制器。因此,对于视图过渡,当你发起过渡时活动的视图控制器在过渡结束时还是保持活动。

For more information about how you can use view controllers to present new content, see View Controller Programming Guide for iOS.

 关于你可以如何使用视图控制器来呈现新内容的更多信息,请看View Controller Programming Guide for iOS.

Changing the Subviews of a View

1、改变一个视图的子视图

Changing the subviews of a view allows you to make moderate changes to the view. For example, you might add or remove subviews to toggle the superview between two different states. By the time the animations finish, the same view is displayed but its contents are now different.

改变一个视图的子视图允许你对视图做适当的改变。 比如,你可以添加或删除子视图来让子视图在两个不同状态之间切换。 当动画结束时,显示相同的视图,但是内容跟之前不同。

In iOS 4 and later, you use the transitionWithView:duration:options:animations:completion: method to initiate a transition animation for a view. In the animations block passed to this method, the only changes that are normally animated are those associated with showing, hiding, adding, or removing subviews. Limiting animations to this set allows the view to create a snapshot image of the before and after versions of the view and animate between the two images, which is more efficient. However, if you need to animate other changes, you can include theUIViewAnimationOptionAllowAnimatedContent option when calling the method. Including that option prevents the view from creating snapshots and animates all changes directly.

在iOS4以及之后的版本中,你可以使用transitionWithView:duration:options:animations:completion:方法来发起一个视图的过渡动画。 传递给该方法的动画块里,发生的改变只动画跟显示,隐藏,添加或删除子视图等相关的通常行为。把动画限制在该行为集允许视图创建视图的前一个版本和后一个版本的快照图片,然后动画这两张图片,这样更有效率。 然而,如果你需要动画其它改变,你可以在调用该方法时包含UIViewAnimationOptionAllowAnimatedContent 选项。包含此选项阻止视图创建快照并直接动画所有改变。

Listing 4-6 is an example of how to use a transition animation to make it seem as if a new text entry page has been added. In this example, the main view contains two embedded text views. The text views are configured identically, but one is always visible while the other is always hidden. When the user taps the button to create a new page, this method toggles the visibility of the two views, resulting in a new empty page with an empty text view ready to accept text. After the transition is complete, the view saves the text from the old page using a private method and resets the now hidden text view so that it can be reused later. The view then arranges its pointers so that it can be ready to do the same thing if the user requests yet another new page.

列表 4-6 是一个例子,关于如何使用一个过渡动画,使它看起来一个新文本输入页已经被添加。 在该例子中,主视图包含了两个内含的文本视图。所有文本视图有着相同配置,但是当一个视图显示时,另一个总是被隐藏。 当用户点击按钮创建一个新页面时,该方法切换两个视图的可视性,导致在一个新空页面里,一个空文本视图准备接受文本。 当过渡完成时,视图从老页面通过一个似有方法保存文本,并重置当前被隐藏的文本视图以便以后能重新使用。然后视图安排其指针,这样如果用户要求另一个新页面时它能做同样的事情。

Listing 4-6  Swapping an empty text view for an existing one

列表 4-6 为一个已经存在的文本视图交换一个空文本视图

- (IBAction)displayNewPage:(id)sender
{
    [UIView transitionWithView:self.view
        duration:1.0
        options:UIViewAnimationOptionTransitionCurlUp
        animations:^{
            currentTextView.hidden = YES;
            swapTextView.hidden = NO;
        }
        completion:^(BOOL finished){
            // Save the old text and then swap the views.
            [self saveNotes:temp];
 
            UIView*    temp = currentTextView;
            currentTextView = swapTextView;
            swapTextView = temp;
        }];
}

If you need to perform view transitions in iOS 3.2 and earlier, you can use thesetAnimationTransition:forView:cache: method to specify the parameters for the transition. The view you pass to that method is the same one you would pass in as the first parameter to thetransitionWithView:duration:options:animations:completion: method. Listing 4-7 shows the basic structure of the animation block you need to create. Note that to implement the completion block shown in Listing 4-6, you would need to configure an animation delegate with a did-stop handler as described in “Configuring an Animation Delegate.”

如果你需要在iOS3.2以及之前的版本里执行视图过渡,你可以使用

setAnimationTransition:forView:cache: 方法来为过渡指定参数。给该方法传递的视图跟传递给transitionWithView:duration:options:animations:completion: 方法的第一个参数一样。列表 4-7 显示了你需要创建的动画块基本结构。注意要想实现Listing 4-6 显示的完成块(completion block), 你可能需要用一个did-stop处理器(handler)配置一个动画委托,参见“Configuring an Animation Delegate.” 

Listing 4-7  Changing subviews using the begin/commit methods

列表 4-7 使用begin/commit 方法来改变子视图

    [UIView beginAnimations:@"ToggleSiblings" context:nil];
    [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:self.view cache:YES];
    [UIView setAnimationDuration:1.0];
 
    // Make your changes
 
    [UIView commitAnimations];

Replacing a View with a Different View

2、用一个不同的视图替换另一个视图

Replacing views is something you do when you want your interface to be dramatically different. Because this technique swaps only views (and not view controllers), you are responsible for designing your application’s controller objects appropriately. This technique is simply a way of presenting new views quickly using some standard transitions.

当你想要你的界面能够动画变化时,你需要替换视图。因为该技术只交换视图(而不是视图控制器),你需要恰当地设计应用程序控制器对象。该技术是使用一些标准过渡快速呈现新视图的一种简单方法。

In iOS 4 and later, you use the transitionFromView:toView:duration:options:completion: method to transition between two views. This method actually removes the first view from your hierarchy and inserts the other, so you should make sure you have a reference to the first view if you want to keep it. If you want to hide views instead of remove them from your view hierarchy, pass the UIViewAnimationOptionShowHideTransitionViews key as one of the options.

在iOS4以及之后的版本中,你可以使用

transitionFromView:toView:duration:options:completion: 方法来过渡两个视图。该方法实际上是从层次结构里删除第一个视图并插入另一个,所以如果你想要保留第一个视图你应该确保你有一个指向第一个视图的引用。 如果你想隐藏视图,而不是从你的视图层次结构里删除它们,传递UIViewAnimationOptionShowHideTransitionViews 关键字作为其中一个选项。

Listing 4-8 shows the code needed to swap between two main views managed by a single view controller. In this example, the view controller’s root view always displays one of two child views (primaryView or secondaryView). Each view presents the same content but does so in a different way. The view controller uses the displayingPrimarymember variable (a Boolean value) to keep track of which view is displayed at any given time. The flip direction changes depending on which view is being displayed.

列表 4-8 显示了交换由一个视图控制器管理的两个主视图所需的代码。在该例子中,视图控制器的根视图总是显示两个子视图(主视图 或 辅助视图)中的一个。每个视图都显示相同的内容,但是以不同方式显示。 视图控制器使用displaying Primary 成员变量(一个布尔值)来保持跟踪在任何给定时间哪个视图被显示。哪个视图被显示决定了翻转方向的改变。

Listing 4-8  Toggling between two views in a view controller

列表 4-8 在一个视图控制器里切换两个视图

- (IBAction)toggleMainViews:(id)sender {
    [UIView transitionFromView:(displayingPrimary ? primaryView : secondaryView)
        toView:(displayingPrimary ? secondaryView : primaryView)
        duration:1.0
        options:(displayingPrimary ? UIViewAnimationOptionTransitionFlipFromRight :
                    UIViewAnimationOptionTransitionFlipFromLeft)
        completion:^(BOOL finished) {
            if (finished) {
                displayingPrimary = !displayingPrimary;
            }
    }];
}

Note: In addition to swapping out views, your view controller code needs to manage the loading and unloading of both the primary and secondary views. For information on how views are loaded and unloaded by a view controller, see View Controller Programming Guide for iOS.

 注意:除了交换视图,你的视图控制器代码需要管理主视图和辅助视图的载入和卸载。关于视图如何被视图控制器加载和卸载的信息,请看 View Controller Programming Guide for iOS.

Linking Multiple Animations Together

四、一起链接多个动画

The UIView animation interfaces provide support for linking separate animation blocks so that they perform sequentially instead of at the same time. The process for linking animation blocks depends on whether you are using the block-based animation methods or the begin/commit methods:

UIView 动画接口提供了对链接多个分离的动画块的支持,这样它们就能按顺序执行而不是在同一时间执行。 链接动画块的过程取决于是使用基于块的动画方法或是begin/commit方法。

An alternative to linking animations together is to use nested animations with different delay factors so as to start the animations at different times. For more information on how to nest animations, see “Nesting Animation Blocks.”

另一种链接多个动画的方法是使用嵌套的动画,在里面采用不同的延迟因子让动画在不同的时间启动。 关于如何嵌套动画的更多信息,请看 “Nesting Animation Blocks.”

Animating View and Layer Changes Together

五、一起动画视图和层发生的改变

Applications can freely mix view-based and layer-based animation code as needed but the process for configuring your animation parameters depends on who owns the layer. Changing a view-owned layer is the same as changing the view itself, and any animations you apply to the layer’s properties respect the animation parameters of the current view-based animation block. The same is not true for layers that you create yourself. Custom layer objects ignore view-based animation block parameters and use the default Core Animation parameters instead.

应用程序可以根据需要自由地混合基于视图和基于层的动画代码,但是配置你的动画参数过程取决于谁拥有层。 改变一个视图拥有的层跟改变视图本身一样,而且你应用到层属性的任何动画代表单签基于视图动画块的动画参数。对于你自己创建的层则跟视图不一样。自定义层对象忽视基于视图的动画块参数,并使用默认的Core Animation 参数来代替。

If you want to customize the animation parameters for layers you create, you must use Core Animation directly. Typically, animating layers using Core Animation involves creating a CABasicAnimation object or some other concrete subclass of CAAnimation. You then add that animation to the corresponding layer. You can apply the animation from either inside or outside a view-based animation block.

如果你想要为你创建的层自定义动画参数,你必须直接使用Core Animation。通常,动画层使用的Core Animation 涉及创建一个CABasicAnimation 对象或CAAnimation 类的一些其它详细子类。 然后你把那个动画添加到相关层。你可以从一个基于视图的动画块内部或外部应用该动画。

Listing 4-9 shows an animation that modifies a view and a custom layer at the same time. The view in this example contains a custom CALayer object at the center of its bounds. The animation rotates the view counter clockwise while rotating the layer clockwise. Because the rotations are in opposite directions, the layer maintains its original orientation relative to the screen and does not appear to rotate significantly. However, the view beneath that layer spins 360 degrees and returns to its original orientation. This example is presented primarily to demonstrate how you can mix view and layer animations. This type of mixing should not be used in situations where precise timing is needed.

列表4-9 显示了一个动画,它同时修改了一个视图和一个自定义层。 例中的视图在它的边界中央包含了一个自定义CALayer 对象。动画在顺时针旋转层的同时逆时针旋转视图。因为旋转方向相反,层相对于屏幕保持其初始方向,不会发生显著旋转。 然而,在那个层之下的视图旋转了360度,返回到它的初始方向。该例子主要说明你可以如何混合视图和层动画。 该混合类型不应该用于精确定时(precise timing)的情况。

Listing 4-9  Mixing view and layer animations

列表 4-9 混合视图动画和层动画

[UIView animateWithDuration:1.0
    delay:0.0
    options: UIViewAnimationOptionCurveLinear
    animations:^{
        // Animate the first half of the view rotation.
        CGAffineTransform  xform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-180));
        backingView.transform = xform;
 
        // Rotate the embedded CALayer in the opposite direction.
        CABasicAnimation*    layerAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
        layerAnimation.duration = 2.0;
        layerAnimation.beginTime = 0; //CACurrentMediaTime() + 1;
        layerAnimation.valueFunction = [CAValueFunction functionWithName:kCAValueFunctionRotateZ];
        layerAnimation.timingFunction = [CAMediaTimingFunction
                        functionWithName:kCAMediaTimingFunctionLinear];
        layerAnimation.fromValue = [NSNumber numberWithFloat:0.0];
        layerAnimation.toValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(360.0)];
        layerAnimation.byValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(180.0)];
        [manLayer addAnimation:layerAnimation forKey:@"layerAnimation"];
    }
    completion:^(BOOL finished){
        // Now do the second half of the view rotation.
        [UIView animateWithDuration:1.0
             delay: 0.0
             options: UIViewAnimationOptionCurveLinear
             animations:^{
                 CGAffineTransform  xform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-359));
                 backingView.transform = xform;
             }
             completion:^(BOOL finished){
                 backingView.transform = CGAffineTransformIdentity;
         }];
}];

Note: In Listing 4-9, you could also create and apply the CABasicAnimation object outside of the view-based animation block to achieve the same results. All of the animations ultimately rely on Core Animation for their execution. Thus, if they are submitted at approximately the same time, they run together.

 注意:Listing 4-9中,你还可以在基于视图的动画块外部创建和应用CABasicAnimation对象来达到相同的结果。所有的动画最终都依赖Core Animation执行。 因此,如果它们差不多同时被递交,它们会在一起运行。

If precise timing between your view and layer based animations is required, it is recommended that you create all of the animations using Core Animation. You may find that some animations are easier to perform using Core Animation anyway. For example, the view-based rotation in Listing 4-9  requires a multistep sequence for rotations of more than 180 degrees, whereas the Core Animation portion uses a rotation value function that rotates from start to finish through a middle value.

如果基于视图和基于层的动画之间要求精确定时(precise timing),推荐你用Core Animation创建所有的动画。 你或许会发现一些动画无论如何都是使用Core Animation比较简单。 比如,Listing 4-9中基于视图的旋转要求一个多步骤序列完成多余180度的旋转,而Core Animation 部分则只需要一个旋转值函数就能实现,它通过一个中间值从开始到结束的旋转。

For more information about how to create and configure animations using Core Animation, see Core Animation Programming Guide and Core Animation Cookbook.

关于如何使用Core Animation来创建和配置动画的更多信息,请看Core Animation Programming Guide and Core Animation Cookbook.

 

posted on 2013-07-24 13:00  cainiaozhang  阅读(992)  评论(0编辑  收藏  举报