An overview of

You can see gorgeous animation effects everywhere in iOS. The process of implementing these animations is not complicated. Today I will take you to see the full picture of iOS animation. Here you can see how iOS uses layers to simplify non-interactive drawing, how to create base animations, keyframes, animation groups, transitions from core animations, how to simplify these animation operations with UIView decorations, and more. In today’s article, you can see how simple and efficient animations are in iOS. Many animations that you wanted to do but had no idea about will become even easier in iOS:

  1. CALayer
    1. Introduction of CALayer
    2. CALayer common attributes
    3. CALayer drawing
  2. Core Animation
    1. Based on the animation
    2. Keyframe animation
    3. Animation group
    4. Animated transitions
    5. Frame by frame animation
  3. UIView animation encapsulation
    1. Based on the animation
    2. Keyframe animation
    3. Animated transitions

CALayer

Introduction of CALayer

Before we get into animation operations we must first understand a common object in animation called ayer. CALayer is included in the QuartzCore framework, a cross-platform framework that works on both iOS and Mac OS X. The essence of Animation development with Core Animation is to convert the contents of CALayer into bitmaps for hardware operation. Therefore, to master Animation operation, one must be familiar with CALayer first.

In the previous article, we used CALayer when we used Quartz 2D drawing. The essence of drawing with drawRect: method is to draw into the layer of UIView, but this process was not experienced in the previous section. But in Core Animation what we’re doing is we’re not doing UIView anymore and we’re doing CALayer directly. The following diagram depicts the relationship between CALayer and UIView. In UIView, there is a layer property as the root layer, on which you can put other sublayers, and all the content that can be seen in UIView is contained in the layer:

Review images

CALayer common attributes

In iOS, CALayer is mainly designed for content display and animation operations. CALayer itself is not included in UIKit and cannot respond to events. Since CALayer was designed with animation in mind, many of its properties can be animated when modified, called “implicit animation properties.” But for the root layer of UIView, property changes don’t animate, because in many cases the root layer acts more like a container, and if it animates its properties it directly affects its sublayers. In addition, the root layer of UIView is completely created by iOS and cannot be recreated, but you can add or remove sublayers to the root layer.

The following table lists the attributes commonly used by CALayer:

attribute instructions Whether implicit animation is supported
anchorPoint The point overlapped with the center point position is called “anchor point”. The description of anchor point is the default position (0.5,0.5) at the center point of the image relative to the ratio of x and Y positions is
backgroundColor Layer background color is
borderColor Border color is
borderWidth Border width is
bounds Size of the layer is
contents Layers display content. For example, images can be displayed as layer content is
contentsRect Layers show the size and position of the content is
cornerRadius radius is
doubleSided Whether to display on the back of the layer. The default is YES no
frame Layer size and position. Implicit animation is not supported, so frame is rarely used in CALayer, and bounds and position are usually used instead no
hidden Whether to hide is
mask Layer mask is
maskToBounds Whether to cut layer boundaries for sublayers. Default is NO is
opacity Transparency, just like the alpha of UIView is
position Layer center, similar to the center of UIView is
shadowColor Shadow color is
shadowOffset Shadow offset is
shadowOpacity Shadow transparency, note that the default is 0 and must be set if shadows are set is
shadowPath Shadow shape is
shadowRadius Shadow blur radius is
sublayers The child layer is
sublayerTransform Sublayer deformation is
transform The layer deformation is
  • The essence of implicit property animation is that changes to these Properties are implicitly implemented by CABasicAnimation by default. See the section “Animatable Properties” in the Xcode help documentation for more details.
  • The frame property is rarely used in CALayer because frames themselves do not support animation effects, and bounds and position are usually used instead.
  • CALayer uses opacity instead of alpha; Center points are represented by position instead of Center.
  • The anchorPoint attribute is the layer’s anchorPoint, which ranges from 0 to 1,0 to 1 and represents the ratio between the x and y axes. This point can always coincide with position. When the center of the layer is fixed, Adjust anchorPoint to adjust the layer’s display position (since it always coincides with Position)

To further illustrate the role of anchorPoint, assume that there is a layer of size 100*100, now at the center point (50,50), from which frame (0,0,100,100) can be derived. As mentioned above, anchorPoint is (0.5,0.5) by default, which coincides with the central point position. In this case, graphic description is used as shown in Figure 1. When the anchorPoint is changed to (0,0), the anchorPoint is at the upper left corner of the layer, but the poition of the center point will not change, so the layer will move to the lower right corner, as shown in figure 2. Then change anchorPoint to (1,1,), position remains unchanged and the anchorPoint is at the lower right corner of the layer, as shown in figure 3.

Review images

Through a simple example below demonstrate the above several attributes, the program initialization phase we define a square, but the rounded path is adjusted for the square side length of the general, make it look is a circle, when click on the screen to modify the layer properties to form animation effects (note in the program without directly modifying UIView layer properties, Because the root layer can’t animate) :

// // kcmainViewController.m // CALayer // // Created by Kenshin Cui on 14-3-22. // Copyright (C) 2014 Kenshin Cui. All  rights reserved. // #import "KCMainViewController.h" #define WIDTH 50 @interface KCMainViewController () @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. [self drawMyLayer]; } #pragma mark drawMyLayer -(void)drawMyLayer{CGSize size=[UIScreen mainScreen].bounds.size; CALayer *layer=[[CALayer alloc]init]; // Set the background color. Since QuartzCore is a cross-platform framework, Cannot use UIColor layer.backgroundColor=[UIColor colorWithRed:0 green:146/255.0 blue:1.0 alpha:1.0]. // Set the center point layer.position=CGPointMake(sie.width /2, sie.height /2); Layer. bounds=CGRectMake(0, 0, WIDTH,WIDTH); Layer. cornerRadius=WIDTH/2; cornerRadius= cornerRadius /2; // Set the shadow layer.shadowcolor =[UIColor grayColor].cgcolor; layer.shadowOffset=CGSizeMake(2, 2); layer.shadowOpacity=.9; BorderColor =[UIColor whiteColor].CGColor; // layer.borderWidth=1; // layer.anchorPoint=CGPointZero; [self.view.layer addSublayer:layer]; } # touch touches :(NSSet *)touches :(UIEvent *)event{touches *touch=[touches anyObject];  CALayer *layer=self.view.layer.sublayers[0]; CGFloat width=layer.bounds.size.width; if (width==WIDTH) { width=WIDTH*4; }else{ width=WIDTH; } layer.bounds=CGRectMake(0, 0, width, width); layer.position=[touch locationInView:self.view]; layer.cornerRadius=width/2; } @endCopy the code

Operation effect:

Review images

CALayer drawing

The previous article focused on drawing using Quartz 2D, which called UIView drawRect: to draw graphics and images. This is essentially drawing on layers, but I’ll focus on drawing directly on layers. The way you draw on layers is basically the same as before, except that the drawRect: method is called by a UIKit component, so you can draw with uiKit-wrapped methods, And the method to draw directly to a layer is not a UIKit call so you can only draw it using the native Core Graphics method.

There are two ways to draw a layer, and no matter which way you draw it you have to call the setNeedDisplay method on your layer (layer method, not UIView method, which we introduced earlier on UIView also has this method)

  1. Draw using the layer agent drawLayer: inContext: method
  2. Draw using the custom layer drawInContext: method

Draw using the proxy method

To draw layers by proxy, specify the layer’s proxy and override the -(void)drawLayer:(CALayer *)layer inContext:(CGContextRef) CTX method in the proxy object. Note that this method is a proxy method but you don’t need to implement a CALayerDelegate manually, because the CALayer definition extends the class of NSObject, and all NSObject objects contain this method. In addition, after setting up the proxy, you must call the setNeedDisplay method of the layer, otherwise the drawn content will not be displayed.

The following code demonstrates drawing an image on a custom layer and setting the image to a circle. This effect is common in many applications, such as the latest version of mobile QQ avatar:

// // kcmainViewController.m // CALayer // // Created by Kenshin Cui on 14-3-22. // Copyright (C) 2014 Kenshin Cui. All  rights reserved. // #import "KCMainViewController.h" #define PHOTO_HEIGHT 150 @interface KCMainViewController () @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; CALayer *layer=[[CALayer alloc]init]; layer.bounds=CGRectMake(0, 0, PHOTO_HEIGHT, PHOTO_HEIGHT); layer.position=CGPointMake(160, 200); layer.backgroundColor=[UIColor redColor].CGColor; layer.cornerRadius=PHOTO_HEIGHT/2; MasksToBounds =YES and cut the layer layer layer.masksToBounds=YES; ShadowColor =[UIColor grayColor].cgcolor; shadowColor=[UIColor grayColor]. // layer.shadowOffset=CGSizeMake(2, 2); // layer.shadowOpacity=1; // Set the border layer.borderColor=[UIColor whiteColor].cgcolor; layer.borderWidth=2; // Set layer agent layer.delegate=self; // Add layer to root layer [self.view.layer addSublayer:layer]; // Call the layer setNeedDisplay, otherwise the proxy method will not be called [layer setNeedsDisplay]; } #pragma mark draws graphics and images to layers. Note that CTX is the graphic context of the layers. -(void)drawLayer:(CALayer *)layer inContext:(CGContextRef) CTX {// NSLog(@"%@",layer); // This layer is the one defined above. CGContextSaveGState(CTX); CGContextScaleCTM(CTX, 1, -1); CGContextTranslateCTM(ctx, 0, -PHOTO_HEIGHT); UIImage *image=[UIImage imageNamed:@"photo.png"]; // Note that this position is relative to the layer and not the screen CGContextDrawImage(CTX, CGRectMake(0, 0, PHOTO_HEIGHT, PHOTO_HEIGHT), image.cgimage); // CGContextFillRect(ctx, CGRectMake(0, 0, 100, 100)); // CGContextDrawPath(ctx, kCGPathFillStroke); CGContextRestoreGState(ctx); } @endCopy the code

Operation effect:

Review images

The drawLayer:inContext: method is used to obtain the drawing layer and the drawing context. In this method all positions are relative to the layer, and the graphic context also refers to the graphic context of the current layer.

It is important to note that circles cannot be displayed without masksToBounds, but this does not apply to other shapes. The reason for this is that when you draw an image onto the layer it will create a new layer and add it to the current layer, so if you set rounded corners to the bottom layer, the bottom layer will have rounded corners, but the sublayer will still be a rectangle. You can only display rounded corners if you set masksToBounds to YES to cut the sublayer from the bottom layer. You can only use masksToBounds if you use UIImageView layer to set rounded corners.

Extension 1- Round image crop with shadow effect

Ounds =YES can be used to display rounded corners, but unfortunately shadows cannot be set. Since masksToBounds=YES means that the outer border is not displayed and the shadow is drawn as the outer border, the two Settings conflict. To solve this problem, use two layers of the same size, one on the bottom for shading and one on the top for displaying the image.

// // kcmainViewController.m // CALayer // // Created by Kenshin Cui on 14-3-22. // Copyright (C) 2014 Kenshin Cui. All  rights reserved. // #import "KCMainViewController.h" #define PHOTO_HEIGHT 150 @interface KCMainViewController () @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; CGPoint position= CGPointMake(160, 200); CGRect bounds=CGRectMake(0, 0, PHOTO_HEIGHT, PHOTO_HEIGHT); CGFloat cornerRadius=PHOTO_HEIGHT/2; CGFloat borderWidth=2; CALayer *layerShadow=[[CALayer alloc]init]; layerShadow.bounds=bounds; layerShadow.position=position; layerShadow.cornerRadius=cornerRadius; layerShadow.shadowColor=[UIColor grayColor].CGColor; layerShadow.shadowOffset=CGSizeMake(2, 1); layerShadow.shadowOpacity=1; layerShadow.borderColor=[UIColor whiteColor].CGColor; layerShadow.borderWidth=borderWidth; [self.view.layer addSublayer:layerShadow]; CALayer *layer=[[CALayer alloc]init]; layer.bounds=bounds; layer.position=position; layer.backgroundColor=[UIColor redColor].CGColor; layer.cornerRadius=cornerRadius; layer.masksToBounds=YES; layer.borderColor=[UIColor whiteColor].CGColor; layer.borderWidth=borderWidth; // Set layer agent layer.delegate=self; // Add layer to root layer [self.view.layer addSublayer:layer]; // Call the layer setNeedDisplay, otherwise the proxy method will not be called [layer setNeedsDisplay]; } #pragma mark draws graphics and images to layers. Note that CTX is the graphic context of the layers. -(void)drawLayer:(CALayer *)layer inContext:(CGContextRef) CTX {// NSLog(@"%@",layer); // This layer is the one defined above. CGContextSaveGState(CTX); CGContextScaleCTM(CTX, 1, -1); CGContextTranslateCTM(ctx, 0, -PHOTO_HEIGHT); UIImage *image=[UIImage imageNamed:@"photo.jpg"]; // Note that this position is relative to the layer and not the screen CGContextDrawImage(CTX, CGRectMake(0, 0, PHOTO_HEIGHT, PHOTO_HEIGHT), image.cgimage); // CGContextFillRect(ctx, CGRectMake(0, 0, 100, 100)); // CGContextDrawPath(ctx, kCGPathFillStroke); CGContextRestoreGState(ctx); } @endCopy the code

Operation effect:

Review images

Extension 2- Layer deformations

As you can see from the code above, drawing an image using Core Graphics will display it upside down, reversing the Graphics context of the layer. A similar method was adopted in the previous article to solve this problem, but it was also mentioned in that article that the correct display could be achieved if the image was rotated 180 degrees along the X axis, but the rotation at that time could not be rotated around the X axis depending on the graphics context. After learning about layers today, you can actually control the rotation of layers directly without resorting to the deformations of the graphics context, and it’s much easier and more intuitive. For the above application, all you need to do is set the layer’s Transform property. It should be noted that transform is CATransform3D, and deformation can be carried out in three dimensions. The use method is similar to the two-dimensional deformation introduced above, and there are corresponding deformation setting methods (e.g. : CATransform3DMakeTranslation (), CATransform3DMakeScale (), CATransform3DMakeRotation ()). The following code through CATransform3DMakeRotation () method on the x axis rotate 180 degrees to solve problem:

// // deformation demo // CALayer // // Created by Kenshin Cui on 14-3-22. // Copyright (C) 2014 Kenshin Cui. All rights reserved. // #import "KCMainViewController.h" #define PHOTO_HEIGHT 150 @interface KCMainViewController () @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; CGPoint position= CGPointMake(160, 200); CGRect bounds=CGRectMake(0, 0, PHOTO_HEIGHT, PHOTO_HEIGHT); CGFloat cornerRadius=PHOTO_HEIGHT/2; CGFloat borderWidth=2; CALayer *layerShadow=[[CALayer alloc]init]; layerShadow.bounds=bounds; layerShadow.position=position; layerShadow.cornerRadius=cornerRadius; layerShadow.shadowColor=[UIColor grayColor].CGColor; layerShadow.shadowOffset=CGSizeMake(2, 1); layerShadow.shadowOpacity=1; layerShadow.borderColor=[UIColor whiteColor].CGColor; layerShadow.borderWidth=borderWidth; [self.view.layer addSublayer:layerShadow]; CALayer *layer=[[CALayer alloc]init]; layer.bounds=bounds; layer.position=position; layer.backgroundColor=[UIColor redColor].CGColor; layer.cornerRadius=cornerRadius; layer.masksToBounds=YES; layer.borderColor=[UIColor whiteColor].CGColor; layer.borderWidth=borderWidth; / / use the layer deformation solve the problem of inverted image layer. The transform = CATransform3DMakeRotation (M_PI, 1, 0, 0); // Set layer agent layer.delegate=self; // Add layer to root layer [self.view.layer addSublayer:layer]; // Call the layer setNeedDisplay, otherwise the proxy method will not be called [layer setNeedsDisplay]; } #pragma mark draws graphics and images to layers. -(void)drawLayer:(CALayer *)layer inContext:(CGContextRef) CTX {// NSLog(@"%@",layer); UIImage *image=[UIImage imageNamed:@"photo.jpg"]; // Note that this position is relative to the layer and not the screen CGContextDrawImage(CTX, CGRectMake(0, 0, PHOTO_HEIGHT, PHOTO_HEIGHT), image.cgimage); } @endCopy the code

In fact, if you just show an image on the layer, you don’t have to bother, just set layer contents, and you don’t have to do the drawing and you don’t have to do the handstand.

// // Layer content Settings // CALayer // // Created by Kenshin Cui on 14-3-22. // Copyright (C) 2014 Kenshin Cui. All Rights reserved. // #import "KCMainViewController.h" #define PHOTO_HEIGHT 150 @interface KCMainViewController () @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; CGPoint position= CGPointMake(160, 200); CGRect bounds=CGRectMake(0, 0, PHOTO_HEIGHT, PHOTO_HEIGHT); CGFloat cornerRadius=PHOTO_HEIGHT/2; CGFloat borderWidth=2; CALayer *layerShadow=[[CALayer alloc]init]; layerShadow.bounds=bounds; layerShadow.position=position; layerShadow.cornerRadius=cornerRadius; layerShadow.shadowColor=[UIColor grayColor].CGColor; layerShadow.shadowOffset=CGSizeMake(2, 1); layerShadow.shadowOpacity=1; layerShadow.borderColor=[UIColor whiteColor].CGColor; layerShadow.borderWidth=borderWidth; [self.view.layer addSublayer:layerShadow]; CALayer *layer=[[CALayer alloc]init]; layer.bounds=bounds; layer.position=position; layer.backgroundColor=[UIColor redColor].CGColor; layer.cornerRadius=cornerRadius; layer.masksToBounds=YES; layer.borderColor=[UIColor whiteColor].CGColor; layer.borderWidth=borderWidth; UIImage *image=[UIImage imageNamed:@"photo.jpg"]; UIImage *image=[UIImage imageNamed:@"photo.jpg"]; // layer.contents=(id)image.CGImage; [layer setContents:(id)image.CGImage]; // Add layer to root layer [self.view.layer addSublayer:layer]; } @endCopy the code

So why bother talking about deformation? Because deformation has a special meaning for animation. In animation development, deformations are often set not directly to transform but via keyPath. This method of setting the nature of the deformation is the same as before, only using KVC can dynamically modify the value of the property, but this method is really common in animation, because it can easily combine several kinds of deformation together. To solve the animation rotation problem, simply change the previous rotation code to the following code:

[layer setValue:@M_PI forKeyPath:@"transform.rotation.x"];Copy the code

Of course, you need to know which key Paths can be set through key path. You can refer to the “CATransform3D Key Paths” section in the Xcode help document for detailed descriptions.

Use custom layers for drawing

To draw on custom layers, you simply write a class that inherits from CALayer and then draw in drawInContext:. As with drawing in the proxy method, the setNeedDisplay method of the layer is called to display the content drawn in the layer, otherwise the drawInContext method will not be called.

As mentioned in the previous article, the essence of drawing in UIView using Quartz 2D is also drawing on layers. To illustrate this, the following illustration of custom layer drawing does not call custom layers directly from view controller. Instead, you add a custom layer to the root layer of the UIView in a UIView (the UIView in this example has nothing to do with custom layer drawing). UIView’s root layer will automatically create a CGContextRef (CALayer essentially uses a bitmap context) while calling the layer broker’s draw (UIView creating layers will automatically set the layer broker to itself) : InContext: method and passes the graph context as an argument to this method. In UIView the draw: inContext: method will be called the drawRect: method, the drawRect: method used in UIGraphicsGetCurrentContext () method to get the context is the context that created earlier.

KCLayer.m

// // kclayer. m // CALayer // // Created by Kenshin Cui on 14-3-22. // Copyright (c) 2014 Kenshin Cui. All Rights reserved. // #import "KCLayer.h" @implementation KCLayer -(void)drawInContext:(CGContextRef)ctx{ NSLog(@"3-drawInContext:"); NSLog(@"CGContext:%@",ctx); // CGContextRotateCTM(ctx, M_PI_4); CGContextSetRGBFillColor(CTX, 135.0/255.0, 232.0/255.0, 84.0/255.0, 1); CGContextSetRGBStrokeColor (CTX, 135.0/255.0, 232.0/255.0, 84.0/255.0, 1); // CGContextFillRect(ctx, CGRectMake(0, 0, 100, 100)); // CGContextFillEllipseInRect(ctx, CGRectMake(50, 50, 100, 100)); CGContextMoveToPoint (CTX, 94.5, 33.5); //// Star Drawing CGContextAddLineToPoint(CTX,104.02, 47.39); CGContextAddLineToPoint (CTX, 120.18, 52.16); CGContextAddLineToPoint (CTX, 109.91, 65.51); CGContextAddLineToPoint (CTX, 110.37, 82.34); CGContextAddLineToPoint (CTX, 94.5, 76.7); CGContextAddLineToPoint (CTX, 78.63, 82.34); CGContextAddLineToPoint (CTX, 79.09, 65.51); CGContextAddLineToPoint (CTX, 68.82, 52.16); CGContextAddLineToPoint (CTX, 84.98, 47.39); CGContextClosePath(ctx); CGContextDrawPath(ctx, kCGPathFillStroke); } @endCopy the code

KCView.m

// // kcview. m // CALayer // // Created by Kenshin Cui on 14-3-22. // Copyright (c) 2014 Kenshin Cui. All Rights reserved. // #import "KCView.h" #import "KCLayer.h" @implementation KCView -(instancetype)initWithFrame:(CGRect)frame{ NSLog(@"initWithFrame:"); if (self=[super initWithFrame:frame]) { KCLayer *layer=[[KCLayer alloc]init]; layer.bounds=CGRectMake(0, 0, 185, 185); Layer. The position = CGPointMake (160284); Layer. backgroundColor=[UIColor colorWithRed:0 green:146/255.0 blue:1.0 alpha:1.0].cgcolor; // Display layer [layer setNeedsDisplay]; [self.layer addSublayer:layer]; } return self; } -(void)drawRect:(CGRect)rect{ NSLog(@"2-drawRect:"); NSLog(@"CGContext:%@",UIGraphicsGetCurrentContext()); // The current graphics context is exactly the [super drawRect:rect] passed in the drawLayer; } -(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{ NSLog(@"1-drawLayer:inContext:"); NSLog(@"CGContext:%@",ctx); [super drawLayer:layer inContext:ctx]; } @endCopy the code

KCMainViewController.m

// // kcmainViewController.m // CALayer // // Created by Kenshin Cui on 14-3-22. // Copyright (C) 2014 Kenshin Cui. All  rights reserved. // #import "KCMainViewController.h" #import "KCView.h" @interface KCMainViewController () @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; KCView *view=[[KCView alloc]initWithFrame:[UIScreen mainScreen].bounds]; BackgroundColor =[UIColor colorWithRed:249.0/255.0 green:249.0/255.0 blue:249.0/255.0 alpha:1]; [self.view addSubview:view]; } @endCopy the code

Operation effect:

Review images

Core Animation

As you all know, it’s pretty easy to create an animation in iOS. You just call up a block of UIView code to create an animation, which is almost impossible to do in other systems. Here is a simple UIView for a picture enlargement animation:

// // kcmainViewController. m // Animation // // Created by Kenshin Cui on 14-3-22. // Copyright (c) 2014 Kenshin Cui. All rights reserved. // #import "KCMainViewController.h" @interface KCMainViewController () @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; UIImage *image=[UIImage imageNamed:@"open2.png"]; UIImageView *imageView=[[UIImageView alloc]init]; imageView.image=image; imageView.frame=CGRectMake(120, 140, 80, 80); [self.view addSubview:imageView]; / / two seconds after the start of a last minute animation [UIView animateWithDuration: 1 delay: 2 options: UIViewAnimationOptionBeginFromCurrentState animations: ^ {  imageView.frame=CGRectMake(80, 100, 160, 160); } completion:nil]; } @endCopy the code

It is very convenient to use the above UIView encapsulation method for animation Settings, but it is not clear how to implement the specific animation, and the above code has some problems that cannot be solved, such as: how to control the animation pause? How to combine animations? .

This is the Core Animation for iOS (included in the Quartz Core framework). In iOS, core animation is divided into several categories: basic animation, keyframe animation, animation group, and transition animation. The relationship of each class is roughly as follows:

Review images

CAAnimation: core animation base class, can not be used directly, responsible for animation running time, speed control, itself implemented CAMediaTiming protocol.

CAPropertyAnimation: Base class for property animation. It cannot be used directly.

CAAnimationGroup: Animation group, animation group is a combination mode design, animation group can be used for unified control of all animation behavior, all animation effects in the group can be executed concurrently.

CATransition: Transition animation, mainly through the filter for animation effect Settings.

CABasicAnimation: Basic animation. Animation parameters are controlled by property modification. Only the initial state and the end state are available.

CAKeyframeAnimation: Keyframe animation, which also controls animation parameters through properties, but differs from basic animation in that it can have multiple state controls.

Basic animation and keyframe animation belong to attribute animation, which produces animation effect by modifying attribute value. Developers only need to set initial value and end value, and the intermediate process animation (also called “tween animation”) is automatically calculated and generated by the system. Different from basic animation, keyframe animation can set multiple attribute values, and the tween animation between each two attributes is automatically completed by the system. Therefore, from this perspective, basic animation can also be regarded as a keyframe animation with two key frames.

Based on the animation

In many cases, basic animations can be used to meet development needs. The UIView code block used in the previous example for zooming in and out of images is also basic animations (in iOS7 UIView also encapsulates keyframe animations), but the UIView decoration method hides more details. If you do not use uiView-wrapped methods, animation creation is generally divided into the following steps:

1. Initialize the animation and set the animation properties

2. Set the initial value (which can be omitted), end value, and other animation properties

3. Animate the layer

Let’s take a moving animation as an example. In this example, click where on the screen a falling flower will fly to.

// // kcmainViewController. m // Animation // // Created by Kenshin Cui on 14-3-22. // Copyright (c) 2014 Kenshin Cui. All rights reserved. // #import "KCMainViewController.h" @interface KCMainViewController (){ CALayer *_layer; } @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; UIImage *backgroundImage=[UIImage imageNamed:@"background.jpg"]; self.view.backgroundColor=[UIColor colorWithPatternImage:backgroundImage]; _layer=[[CALayer alloc]init]; _layer.bounds=CGRectMake(0, 0, 10, 20); _layer.position=CGPointMake(50, 150); _layer.contents=(id)[UIImage imageNamed:@"petal.png"].CGImage; [self.view.layer addSublayer:_layer]; } #pragma mark -(void)translatonAnimation:(CGPoint)location{//1. Create the animation and specify the properties CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"position"]; // basicanimation.fromValue =[NSNumber numberWithInteger:50]; / / can not set, the default for the layer initial state basicAnimation. ToValue = [NSValue valueWithCGPoint: location]. Basicanimation.duration =5.0; // Set other animation properties basicanimation.duration =5.0; / / animation time for 5 seconds. / / basicAnimation repeatCount = HUGE_VALF; / / set the repetitions, HUGE_VALF as infinity, cycle animation effect / / basicAnimation removedOnCompletion = NO. Add the animation to the layer. Note that the key is equivalent to the name of the animation. Later when get the animation, you can use this name for [_layer addAnimation: basicAnimation forKey: @ "KCBasicAnimation_Translation"]. } # create view -(void)touch began :(NSSet *)touches :(UIEvent *) view {touch * touches. AnyObject; CGPoint location= [touch locationInView:self.view]; / / create and start animation [self translatonAnimation: location]. } @endCopy the code



Operation effect:

Review images

A basic animation effect is implemented above, but there is a problem with this animation: after the animation is finished, the animation layer is returned to its original position. Of course, the UIView method does not have this problem. How to solve this problem?

As mentioned above, the essence of layer animation is to transform the content inside a layer into a bitmap and form an animation effect through hardware operation. In fact, there is no change in the layer itself. In the animation above, the layer does not change its position due to the animation effect (nor does it change its size for scaling animations), so the layer remains in its original position after the animation is completed. If this layer is in a UIView, you’ll notice that the UIView click event that you want to trigger when the UIView moves can only be clicked on the original location (even if it’s moved to another location), because its position never changes. Of course, there are many ways to solve this problem, but here you can reset the position of the animation after it is finished.

// // kcmainViewController. m // Animation // // Created by Kenshin Cui on 14-3-22. // Copyright (c) 2014 Kenshin Cui. All rights reserved. // #import "KCMainViewController.h" @interface KCMainViewController (){ CALayer *_layer; } @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; UIImage *backgroundImage=[UIImage imageNamed:@"background.jpg"]; self.view.backgroundColor=[UIColor colorWithPatternImage:backgroundImage]; _layer=[[CALayer alloc]init]; _layer.bounds=CGRectMake(0, 0, 10, 20); _layer.position=CGPointMake(50, 150); _layer.contents=(id)[UIImage imageNamed:@"petal.png"].CGImage; [self.view.layer addSublayer:_layer]; } #pragma mark -(void)translatonAnimation:(CGPoint)location{//1. Create the animation and specify the properties CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"position"]; // basicanimation.fromValue =[NSNumber numberWithInteger:50]; / / can not set, the default for the layer initial state basicAnimation. ToValue = [NSValue valueWithCGPoint: location]. Basicanimation.duration =5.0; // Set other animation properties basicanimation.duration =5.0; / / animation time for 5 seconds. / / basicAnimation repeatCount = HUGE_VALF; / / set the repetitions, HUGE_VALF as infinity, cycle animation effect / / basicAnimation removedOnCompletion = NO. Basicanimation.delegate =self; basicAnimation.delegate=self; / / store the current position at the end of the animation using [basicAnimation setValue: [NSValue valueWithCGPoint: location] forKey: @ "KCBasicAnimationLocation"]. //3. Add the animation to the layer. Later when get the animation, you can use this name for [_layer addAnimation: basicAnimation forKey: @ "KCBasicAnimation_Translation"]. } # create view -(void)touch began :(NSSet *)touches :(UIEvent *) view {touch * touches. AnyObject; CGPoint location= [touch locationInView:self.view]; / / create and start animation [self translatonAnimation: location]. } #pragma mark -(void)animationDidStart:(CAAnimation *)anim{NSLog(@"animation(%@)) start.\r_layer.frame=%@",anim,NSStringFromCGRect(_layer.frame)); NSLog(@"%@",[_layer animationForKey:@"KCBasicAnimation_Translation"]); } #pragma mark end of animation -(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ NSLog(@"animation(%@) stop.\r_layer.frame=%@",anim,NSStringFromCGRect(_layer.frame)); _layer.position=[[anim valueForKey:@"KCBasicAnimationLocation"] CGPointValue]; } @endCopy the code

Add a custom property “KCBasicAnimationLocation” to the animation to store the animation’s end location before the animation starts, and then set the animation’s position to the end location after the animation ends.

Another problem you might notice if you run the code above is that the animation will start moving again from the beginning to the end. This problem arises because, as mentioned earlier, for non-root layers, setting the animatable property of the layer (position is reset after the animation, and position is animatable) will produce an animation effect. There are two ways to solve this problem: turn off layer implicit animation and set the animation layer to root. Obviously you can’t do the latter here, because the root layer is currently used as the background for the animation.

To turn off implicit animation, use the animation transaction CATransaction. Turn off implicit animation within the transaction. For example, the code above could be changed to:

#pragma mark -(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{NSLog(@"animation(%@) stop.\r_layer.frame=%@",anim,NSStringFromCGRect(_layer.frame)); // start transaction [CATransaction begin]; // Disable implicit animation [CATransaction setDisableActions:YES]; _layer.position=[[anim valueForKey:@"KCBasicAnimationLocation"] CGPointValue]; // Commit transaction [CATransaction commit]; }Copy the code

By resetting the position of the animation in the animationDidStop above major close to illustrate an implicit animation and animation events between the content, a friend found this way is likely to appear in animation after running from the origin moment back to the process, at the end of the first, didn’t found this problem in the debug, thank the friends here. To solve this problem, you must first set fromValue, and then set position to the end position before the animation starts (you must also turn off implicit animation). But here is mainly for the purpose of learning, real development when do pan animation directly use implicit animation, there is no need to bother.

Of course, the animation above is also a little stiff, because falling flowers may not only be free fall movement, itself due to air resistance, external wind will also cause falling flowers in the air rotation, swing, etc., here may wish to add a rotating animation layer. As for layer rotation, we have already shown how to set the layer rotation content using the key path. It is important to emphasize that the layer deformations are based on anchor points. For a rotation, the center of the rotation is the anchor point of the layer.

// // kcmainViewController. m // Animation // // Created by Kenshin Cui on 14-3-22. // Copyright (c) 2014 Kenshin Cui. All rights reserved. // #import "KCMainViewController.h" @interface KCMainViewController (){ CALayer *_layer; } @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; UIImage *backgroundImage=[UIImage imageNamed:@"background.jpg"]; self.view.backgroundColor=[UIColor colorWithPatternImage:backgroundImage]; _layer=[[CALayer alloc]init]; _layer.bounds=CGRectMake(0, 0, 10, 20); _layer.position=CGPointMake(50, 150); _layer. AnchorPoint = CGPointMake (0.5, 0.6); // Set anchor _layer.contents=(id)[UIImage imageNamed:@"petal. PNG "]. [self.view.layer addSublayer:_layer]; } #pragma mark -(void)translatonAnimation:(CGPoint)location{//1. Create the animation and specify the properties CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"position"]; // basicAnimation. FromValue =[NSNumber numberWithInteger:50]; / / can not set, the default for the layer initial state basicAnimation. ToValue = [NSValue valueWithCGPoint: location]. Basicanimation.duration =5.0; // Set other animation properties basicanimation.duration =5.0; / / animation time for 5 seconds. / / basicAnimation repeatCount = HUGE_VALF; / / set the repetitions, HUGE_VALF as infinity, cycle animation effect / / basicAnimation removedOnCompletion = NO. Basicanimation.delegate =self; basicAnimation.delegate=self; / / store the current position at the end of the animation using [basicAnimation setValue: [NSValue valueWithCGPoint: location] forKey: @ "KCBasicAnimationLocation"]. //3. Add the animation to the layer. Later when get the layer, you can use this name for [_layer addAnimation: basicAnimation forKey: @ "KCBasicAnimation_Translation"]. } #pragma mark -(void)rotationAnimation{//1. CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"transform.rotation. Z "]; // basicAnimation. FromValue =[NSNumber numberWithInt:M_PI_2]; basicAnimation.toValue=[NSNumber numberWithFloat:M_PI_2*3]; Basicanimation.duration =6.0; basicanimation.duration =6.0; basicAnimation.autoreverses=true; // Add the animation to the layer. Note that the key is the same as the name of the animation. Later when get the animation, you can use this name for [_layer addAnimation: basicAnimation forKey: @ "KCBasicAnimation_Rotation"]. } # create view -(void)touch began :(NSSet *)touches :(UIEvent *) view {touch * touches. AnyObject; CGPoint location= [touch locationInView:self.view]; / / create and start animation [self translatonAnimation: location]. [self rotationAnimation]; } #pragma mark -(void)animationDidStart:(CAAnimation *)anim{NSLog(@"animation(%@)) start.\r_layer.frame=%@",anim,NSStringFromCGRect(_layer.frame)); NSLog(@"%@",[_layer animationForKey:@"KCBasicAnimation_Translation"]); } #pragma mark end of animation -(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ NSLog(@"animation(%@) stop.\r_layer.frame=%@",anim,NSStringFromCGRect(_layer.frame)); // start transaction [CATransaction begin]; // Disable implicit animation [CATransaction setDisableActions:YES]; _layer.position=[[anim valueForKey:@"KCBasicAnimationLocation"] CGPointValue]; // Commit transaction [CATransaction commit]; } @endCopy the code

The above code combines the two animation operations. Note that the proxy is set only for the moving animation, but not for the rotation animation, otherwise the proxy method will execute twice. Since the rotation animation will be executed in an infinite loop (the number of repeats is set as infinite), and the execution time of the two animations is not necessarily related, so the movement may still be rotating after stopping, in order to make the rotation animation stop after stopping, it is necessary to use the animation pause and resume method.

The core animation runs with a media time concept, assuming a rotation animation takes 60 seconds to rotate once, then the media time is 15 seconds when the animation is rotated 90 degrees. If you want to pause the animation, just set the media time offset to 15 seconds and set the animation speed to 0 to stop the animation. Similarly, if you need to resume the animation after another 60 seconds (media time is 75 seconds), just set the animation start time to the current media time of 75 seconds minus the pause time (which is the offset of the previous stop-motion animation) for 15 seconds (start time =75-15=60 seconds). The animation recalculates the state after 60 seconds and starts running again, with the offset reset to 0 and the speed set to 1. What really stops the animation and resumes the animation is the adjustment of the animation speed, the media time offset, and the start time of the resume to make the animation more consistent.

The following code demonstrates how the rotation animation pauses after the move animation and resumes when the animation is clicked again (note that clicking the screen again during the move pauses the move animation and the rotation animation, and clicking again resumes both animations). Click the screen again and you can only resume the rotation animation, because the movement animation has ended instead of being paused.

// // kcmainViewController. m // Animation // // Created by Kenshin Cui on 14-3-22. // Copyright (c) 2014 Kenshin Cui. All rights reserved. // #import "KCMainViewController.h" @interface KCMainViewController (){ CALayer *_layer; } @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; UIImage *backgroundImage=[UIImage imageNamed:@"background.jpg"]; self.view.backgroundColor=[UIColor colorWithPatternImage:backgroundImage]; _layer=[[CALayer alloc]init]; _layer.bounds=CGRectMake(0, 0, 10, 20); _layer.position=CGPointMake(50, 150); _layer. AnchorPoint = CGPointMake (0.5, 0.6); // Set anchor _layer.contents=(id)[UIImage imageNamed:@"petal. PNG "]. [self.view.layer addSublayer:_layer]; } #pragma mark -(void)translatonAnimation:(CGPoint)location{//1. Create the animation and specify the properties CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"position"]; // basicAnimation. FromValue =[NSNumber numberWithInteger:50]; / / can not set, the default for the layer initial state basicAnimation. ToValue = [NSValue valueWithCGPoint: location]. Basicanimation.duration =5.0; // Set other animation properties basicanimation.duration =5.0; / / animation time for 5 seconds. / / basicAnimation repeatCount = HUGE_VALF; / / set the repetitions, HUGE_VALF as infinity, cycle animation effect basicAnimation. RemovedOnCompletion = NO; Basicanimation.delegate =self; basicAnimation.delegate=self; / / store the current position at the end of the animation using [basicAnimation setValue: [NSValue valueWithCGPoint: location] forKey: @ "KCBasicAnimationLocation"]. //3. Add the animation to the layer. Later when get the layer, you can use this name for [_layer addAnimation: basicAnimation forKey: @ "KCBasicAnimation_Translation"]. } #pragma mark -(void)rotationAnimation{//1. CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"transform.rotation. Z "]; // basicAnimation. FromValue =[NSNumber numberWithInt:M_PI_2]; basicAnimation.toValue=[NSNumber numberWithFloat:M_PI_2*3]; Basicanimation.duration =6.0; basicanimation.duration =6.0; basicAnimation.autoreverses=true; / / rotation in rotation to its original position after basicAnimation. RepeatCount = HUGE_VALF; / / set the infinite loop basicAnimation. RemovedOnCompletion = NO; // basicAnimation.delegate=self; / / 4. The animation is added to the layer and pay attention to the key effect of animation is named, later won the animation can use this name for [_layer addAnimation: basicAnimation forKey: @ "KCBasicAnimation_Rotation"]. } # create view -(void)touch began :(NSSet *)touches :(UIEvent *) view {touch * touches. AnyObject; CGPoint location= [touch locationInView:self.view]; CAAnimation *animation= [_layer animationForKey:@"KCBasicAnimation_Translation"]; if(animation){ if (_layer.speed==0) { [self animationResume]; }else{ [self animationPause]; }} else {/ / and start animation creation [self translatonAnimation: location]. [self rotationAnimation]; }} #pragma mark -(void)animationPause{ There is no need to CFTimeInterval interval = [_layer convertTime: CACurrentMediaTime () fromLayer: nil]; // Set the time offset to ensure that the pause stays at the rotation position [_layer setTimeOffset:interval]; // Set speed to 0, pause animation _layer.speed=0; } #pragma mark animationResume -(void)animationResume{CFTimeInterval beginTime= CACurrentMediaTime() -_layer.timeoffset;  // Set offset _layer.timeOffset=0; BeginTime =beginTime; _layer.speed=1.0; } #pragma mark -(void)animationDidStart:(CAAnimation *)anim{NSLog(@"animation(%@)) start.\r_layer.frame=%@",anim,NSStringFromCGRect(_layer.frame)); NSLog(@"%@",[_layer animationForKey:@"KCBasicAnimation_Translation"]); } #pragma mark end of animation -(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ NSLog(@"animation(%@) stop.\r_layer.frame=%@",anim,NSStringFromCGRect(_layer.frame)); // start transaction [CATransaction begin]; // Disable implicit animation [CATransaction setDisableActions:YES]; _layer.position=[[anim valueForKey:@"KCBasicAnimationLocation"] CGPointValue]; // Commit transaction [CATransaction commit]; // Pause animation [self animationPause]; } @endCopy the code

Operation effect:

Review images

Note:

  • Animation pausing applies to the layer rather than to an animation on the layer.
  • To animate an infinite loop, the removedOnCompletion property of the animation must be set to NO, otherwise the animation will be destroyed once it runs.

Keyframe animation

Those familiar with Flash development should be familiar with keyframe animation, which is often used in Flash development. Keyframe animation is in the process of animation control developers to specify the main state of animation, as to how each state between animation by the system automatic operation complement (each system formed between two key frames of animation called “fill between animation”), the benefits of this animation is developers need not control each animation frames are individually, and as long as the state concerned with several key frames.

The development of keyframe animation can be divided into two forms: one is to control the keyframe by setting different attribute values; the other is to control the keyframe by drawing paths. The latter takes precedence over the former, and the attribute value is no longer in effect if a path is set.

In fact, the process of falling flowers is not natural for the previous animation effect. Obviously, it can not fall in a straight line in real life. Here we can control its falling properties through the values attribute of the keyframe animation. Suppose the falling process is shown as follows:

Review images

Here we need to set four keyframes (the four key points in the figure). The code is as follows (the animation creation process is basically the same as the basic animation) :

// // Set keyframe Animation with values // Animation // // Created by Kenshin Cui on 14-3-22. // Copyright (c) 2014 Kenshin Cui. All rights reserved. // #import "KCMainViewController.h" @interface KCMainViewController (){ CALayer *_layer; } @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; UIImage *backgroundImage=[UIImage imageNamed:@"background.jpg"]; self.view.backgroundColor=[UIColor colorWithPatternImage:backgroundImage]; _layer=[[CALayer alloc]init]; _layer.bounds=CGRectMake(0, 0, 10, 20); _layer.position=CGPointMake(50, 150); _layer.contents=(id)[UIImage imageNamed:@"petal.png"].CGImage; [self.view.layer addSublayer:_layer]; // Create an animation [self translationAnimation]; } #pragma mark keyframe animation -(void)translationAnimation{//1. CAKeyframeAnimation *keyframeAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"]; NSValue *key1=[NSValue valueWithCGPoint:_layer.position]; //2. / / the initial value for key frame animation can't omit NSValue * key2 = [NSValue valueWithCGPoint: CGPointMake (80, 220)]. NSValue *key3=[NSValue valueWithCGPoint:CGPointMake(45, 300)]; NSValue *key4=[NSValue valueWithCGPoint:CGPointMake(55, 400)]; NSArray *values=@[key1,key2,key3,key4]; keyframeAnimation.values=values; / / set the other properties keyframeAnimation. Duration = 8.0; keyframeAnimation.beginTime=CACurrentMediaTime()+2; / / set delay for 2 seconds to perform / / 3. The animation is added to the layer and add animation animation should be executed after [_layer addAnimation: keyframeAnimation forKey: @ "KCKeyframeAnimation_Position"]. } @endCopy the code

Run effect (note that the layer position is not set to the end of the animation at the end of the run) :

Review images

The above way is better than the use of basic animation in front of some, but there are still problems, that is, the path of falling flowers is straight, of course, the straight line is automatically formed according to the four key frames set up in the program, so how to let it fall along the curve? This is the second type of keyframe animation, which is controlled by drawing paths. Suppose falling flowers follow the following curved path:

Review images

Of course, this is a Bezier curve, after learning the previous article should be familiar with this kind of curve, the following is the concrete implementation code:

// // Set keyframe Animation through path // Animation // // Created by Kenshin Cui on 14-3-22. // Copyright (c) 2014 Kenshin Cui. All Rights  reserved. // #import "KCMainViewController.h" @interface KCMainViewController (){ CALayer *_layer; } @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; UIImage *backgroundImage=[UIImage imageNamed:@"background.jpg"]; self.view.backgroundColor=[UIColor colorWithPatternImage:backgroundImage]; _layer=[[CALayer alloc]init]; _layer.bounds=CGRectMake(0, 0, 10, 20); _layer.position=CGPointMake(50, 150); _layer.contents=(id)[UIImage imageNamed:@"petal.png"].CGImage; [self.view.layer addSublayer:_layer]; // Create an animation [self translationAnimation]; } #pragma mark keyframe animation -(void)translationAnimation{//1. CAKeyframeAnimation *keyframeAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"]; CGPathRef path=CGPathCreateMutable(); CGPathMoveToPoint(path, NULL, _layer.position.x, _layer.position.y); // Move to start point CGPathAddCurveToPoint(path, NULL, 160, 280, -30, 300, 55, 400); KeyframeAnimation. Path =path; // Set the path property CGPathRelease(path); / / release the path object / / set the other attributes keyframeAnimation. Duration = 8.0; keyframeAnimation.beginTime=CACurrentMediaTime()+5; / / set delay for 2 seconds to perform / / 3. The animation is added to the layer and add animation animation should be executed after [_layer addAnimation: keyframeAnimation forKey: @ "KCKeyframeAnimation_Position"]. } @endCopy the code

Run effect (note that the layer position is not set to the end of the animation at the end of the run) :

Review images

It looks a little less rigid, but it’s important to note here that the keyframe animation system for path types starts at the location where the path is drawn and ends there. If the path above is not a Bezier curve but a rectangular path then it will start at the top left corner of the rectangle and return clockwise around the top left corner; If the specified path is an ellipse, the animation runs from the right side of the ellipse (0 degrees) clockwise back to the right.

Complement — Other attributes

In keyframe animation there are some animation properties beginners are often more confused, here specifically for these properties to do a brief introduction.

KeyTimes: Time control for each key frame. Values was used to set four keyframes, and by default the interval between two frames is 8/(4-1) seconds. If you want to control the animation to take 4 seconds from frame 1 to frame 2, 2 seconds from frame 2 to frame 3, and 2 seconds from frame 3 to frame 4, you can do this with keyTimes. KeyTimes stores the percentage of time occupied points, and can be set to 0.0, 0.5, 0.75, 1.0 (of course must be converted to NSNumber), that is, 1 to 2 frames run to 50% of the total time, 2 to 3 frames run to 75% of the total time, 3 to 4 frames run to the end of 8 seconds.

CaculationMode: animation calculation mode. In the case of keyValues above, the reason frames 1 to 2 form a continuous animation instead of going directly from frame 1 to frame 2 through 8/3 seconds is because the animation mode is continuous (value is kCAAnimationLinear, which is the default value for the calculation mode). If you specify kCAAnimationDiscrete you will see the animation go from frame 1 to frame 2 in 8/3 seconds without any transition. Other animation modes include a kCAAnimationCubic paced (even paced, ignoring keyTimes), kCAAnimationCubic (even paced, even paced, for positional change keyframes), and kCAAnimationCubic (even paced, even paced).

The following diagram depicts the relationship between several animation modes (the horizontal axis is the running time and the vertical axis is the animation properties [such as position, transparency, etc.]) :

Review images

Animation group

Actual development in complex movement, the movement of an object is often less movement of the single attribute, but just for each animation animation attributes set properties can only set one at a time when the animation control (whether based animation and keyframe animation), so that to be a compound motion animation must create multiple attribute of the animation. For one or two combinations of animations it may be easy to handle, but for more combinations of animations it can become cumbersome, and animation groups are created based on such situations. Animation group is a combination of a series of animation, all the animation added to the animation group are controlled by the animation group, so that the common behavior of all kinds of animation can be unified control without separate Settings, and each animation in the animation group can be executed concurrently, together to build a complex animation effect.

Animation groups are not complicated to use. First create a single animation (either a base animation or a keyframe animation), then add the base animation to the animation group, and finally add the animation group to the layer.

In front of the keyframe animation, although the effect of path animation looks very smooth, but the rotation movement of the falling flower itself is not there. Here, it may as well combine the rotation animation and path keyframe animation of the basic animation to make the whole animation look more harmonious and smooth.

// // Animation group // Animation // // Created by Kenshin Cui on 14-3-22. // Copyright (c) 2014 Kenshin Cui. All rights reserved.  // #import "KCMainViewController.h" @interface KCMainViewController (){ CALayer *_layer; } @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; UIImage *backgroundImage=[UIImage imageNamed:@"background.jpg"]; self.view.backgroundColor=[UIColor colorWithPatternImage:backgroundImage]; _layer=[[CALayer alloc]init]; _layer.bounds=CGRectMake(0, 0, 10, 20); _layer.position=CGPointMake(50, 150); _layer.contents=(id)[UIImage imageNamed:@"petal.png"].CGImage; [self.view.layer addSublayer:_layer]; // Create animation [self groupAnimation]; } #pragma mark base rotationAnimation -(CABasicAnimation *)rotationAnimation{CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; CGFloat toValue=M_PI_2*3; basicAnimation.toValue=[NSNumber numberWithFloat:M_PI_2*3]; / / basicAnimation. Duration = 6.0; basicAnimation.autoreverses=true; basicAnimation.repeatCount=HUGE_VALF; basicAnimation.removedOnCompletion=NO; [basicAnimation setValue:[NSNumber numberWithFloat:toValue] forKey:@"KCBasicAnimationProperty_ToValue"]; return basicAnimation; } #pragma mark keyframeAnimation -(CAKeyframeAnimation *)translationAnimation{CAKeyframeAnimation *keyframeAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"]; CGPoint endPoint= CGPointMake(55, 400); CGPathRef path=CGPathCreateMutable(); CGPathMoveToPoint(path, NULL, _layer.position.x, _layer.position.y); CGPathAddCurveToPoint(path, NULL, 160, 280, -30, 300, endPoint.x, endPoint.y); keyframeAnimation.path=path; CGPathRelease(path); [keyframeAnimation setValue:[NSValue valueWithCGPoint:endPoint] forKey:@"KCKeyframeAnimationProperty_EndPosition"]; return keyframeAnimation; } #pragma mark creates an animation group -(void)groupAnimation{//1. CAAnimationGroup *animationGroup=[CAAnimationGroup animation]; CABasicAnimation *basicAnimation=[self rotationAnimation]; CAKeyframeAnimation *keyframeAnimation=[self translationAnimation]; animationGroup.animations=@[basicAnimation,keyframeAnimation]; animationGroup.delegate=self; AnimationGroup. Duration = 10.0; Animationgroup. beginTime=CACurrentMediaTime()+5; / / implementation of five seconds delay / / 3. Add animation to layer [_layer addAnimation: animationGroup forKey: nil]; } #pragma mark - -(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ CAAnimationGroup *animationGroup=(CAAnimationGroup *)anim; CABasicAnimation *basicAnimation=animationGroup.animations[0]; CAKeyframeAnimation *keyframeAnimation=animationGroup.animations[1]; CGFloat toValue=[[basicAnimation valueForKey:@"KCBasicAnimationProperty_ToValue"] floatValue]; CGPoint endPoint=[[keyframeAnimation valueForKey:@"KCKeyframeAnimationProperty_EndPosition"] CGPointValue]; [CATransaction begin]; [CATransaction setDisableActions:YES]; // Set the animation final state _layer.position=endPoint; _layer.transform=CATransform3DMakeRotation(toValue, 0, 0, 1); [CATransaction commit]; } @endCopy the code

Operation effect:

Review images

Animated transitions

A transition animation is a transition from one scene to another in the form of animation. The use of transition animation is generally divided into the following steps:

1. Create transitions

2. Set the transition type, subtype (optional), and other properties

3. Set the new view after the transition and add animation to the layer

The following table lists the commonly used transition types (note that the private API is an animation type that Is not officially disclosed by Apple, but is still available through the app) :

Animation types instructions Corresponding to a constant Whether direction setting is supported
Public API      
fade fade-out kCATransitionFade is
movein The new view is moved to the old view kCATransitionMoveIn is
push New view pushes out old view kCATransitionPush is
reveal Remove the old view to display the new view kCATransitionReveal is
Private API   Private apis can only be accessed through strings  
cube Cube flip effect There is no is
oglFlip Rollover effect There is no is
suckEffect Contraction effect There is no no
rippleEffect Droplet ripple effect There is no no
pageCurl Page up effect There is no is
pageUnCurl Scroll down effect There is no is
cameralIrisHollowOpen Camera opening Effect There is no no
cameraIrisHollowClose Camera Closing Effect There is no no

There are also subtypes for animation types that support orientation:

Animation subtype instructions
kCATransitionFromRight Take a turn on the right
kCATransitionFromLeft Turn left
kCATransitionFromTop Transition from the top
kCATransitionFromBottom Transition from the bottom

In the previous article “IOS Development Series — Infinite Loop Image Browser” we spent a lot of time on performance optimization to make an infinite loop image browser with UIScrollView. Here we use a transition animation to make a beautiful infinite loop image browser using a UIImageView.

// // kcmainViewController.m // TransitionAnimation // // Created by Kenshin Cui on 14-3-12. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import "KCMainViewController.h" #define IMAGE_COUNT 5 @interface KCMainViewController (){ UIImageView *_imageView; int _currentIndex; } @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; _imageView=[[UIImageView alloc]init]; _imageView.frame=[UIScreen mainScreen].applicationFrame; _imageView.contentMode=UIViewContentModeScaleAspectFit; _imageView.image=[UIImage imageNamed:@"0.jpg"]; // Default image [self.view addSubview:_imageView]; // Add gesture UISwipeGestureRecognizer *leftSwipeGesture=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(leftSwipe:)]; leftSwipeGesture.direction=UISwipeGestureRecognizerDirectionLeft; [self.view addGestureRecognizer:leftSwipeGesture]; UISwipeGestureRecognizer *rightSwipeGesture=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(rightSwipe:)]; rightSwipeGesture.direction=UISwipeGestureRecognizerDirectionRight; [self.view addGestureRecognizer:rightSwipeGesture]; } #pragma mark -(void)leftSwipe:(UISwipeGestureRecognizer *) Gesture {[self transitionAnimation:YES]; } #pragma Mark -(void)rightSwipe:(UISwipeGestureRecognizer *) Gesture {[self transitionAnimation:NO]; } #pragma mark -(void)transitionAnimation:(BOOL)isNext{//1. CATransition *transition=[[CATransition alloc]init]; Type =@"cube"; //2. Set the animation type. Note that only strings can be used for animation types that are not public by Apple. Subtype =kCATransitionFromRight; // Set subtype if (isNext) {transition.subtype=kCATransitionFromRight; }else{ transition.subtype=kCATransitionFromLeft; } // Set animate transition.duration=1.0f; Imageview. image=[self getImage:isNext]; [_imageView.layer addAnimation:transition forKey:@"KCTransitionAnimation"]; } #pragma mark gets the current image -(UIImage *)getImage:(BOOL)isNext{if (isNext) {_currentIndex=(_currentIndex+1)%IMAGE_COUNT; }else{ _currentIndex=(_currentIndex-1+IMAGE_COUNT)%IMAGE_COUNT; } NSString *imageName=[NSString stringWithFormat:@"%i.jpg",_currentIndex]; return [UIImage imageNamed:imageName]; } @endCopy the code

Operation effect:

Review images

The code is simple, but the results and performance are amazing. Of course, demo code is limited, other types of animation we can achieve their own, the effect is very beautiful.

Frame by frame animation

Most of the animation types in core animation have been introduced before, but those who have done animation processing know that there is another animation type in animation production, “frame by frame animation”. When it comes to frame-by-frame animation, the first thing that comes to mind is UIImageView. Set the animationImages property of UIImageView and call its startAnimating method to play the group of images. Of course, this method can achieve frame-by-frame animation in some scenarios, but it also has significant performance issues, and once the process is set up in the middle of the image, you can’t control it. Of course, maybe some friends will think of using the iOS timer NSTimer to regularly update the picture to achieve the effect of frame by frame animation. This approach does solve the problem of UIImageView loading a large number of images at once and makes the playback process manageable. The only drawback is that timer method calls can sometimes cause problems with animation continuity because the current system is performing some time-consuming task.

While the frame-by-frame animation type is not provided directly in core animation, CADisplayLink, a related object used to complete frame-by-frame animation, is provided. CADisplayLink is a timer, but unlike NSTimer, CADisplayLink’s refresh cycle is exactly the same as the screen’s. For example, while the screen refresh rate on iOS is 60 times per second, CADisplayLink’s refresh rate is the same as the screen refresh rate, so frame-by-frame animations (also known as “clock animations”) are completely unaware of the animation stagnation.

As stated in the opening iOS development series – overview of iOS Application Development, an iOS application enters a message loop (called the “main run loop”) as soon as it runs, and the entire application enters an infinite loop waiting for user input. Adding CADisplayLink to the main run cycle queue keeps its clock cycle the same as the main run cycle, which is the screen refresh cycle. After CADisplayLink is added to the main run loop queue, the target method is called in a loop, where the view content is updated to complete frame-by-frame animation.

Of course, it has to be emphasized that the performance of frame-by-frame animation is bound to be low, but frame-by-frame animation has to be used for the movement of some things, such as human movement, which is a highly complex movement, and it is impossible to solve basic animation and keyframe animation. Therefore, we must pay attention to reduce the algorithm complexity as much as possible in the loop method, and at the same time ensure that the peak memory in the loop as low as possible. Here is a frame-by-frame animation of the movement of a fish.

// // kcmainViewController. m // DisplayLink // // Created by Kenshin Cui on 14-3-22. // Copyright (C) 2014 Kenshin Cui.  All rights reserved. // #import "KCMainViewController.h" #define IMAGE_COUNT 10 @interface KCMainViewController (){ CALayer *_layer; int _index; NSMutableArray *_images; } @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; Self.view.layer. contents=(id)[UIImage imageNamed:@"bg.png"].cgImage; // Create image display layer _layer=[[CALayer alloc]init]; _layer.bounds=CGRectMake(0, 0, 87, 32); _layer.position=CGPointMake(160, 284); [self.view.layer addSublayer:_layer]; _images=[NSMutableArray array] _images=[NSMutableArray array] _images=[NSMutableArray array]; for (int i=0; i"fish%i.png",i]; UIImage *image=[UIImage imageNamed:imageName]; [_images addObject:image]; } / / define the clock object CADisplayLink * displayLink = [CADisplayLink displayLinkWithTarget: self selector: @ the selector (step)]; / / add the clock object to the main operating cycle [displayLink addToRunLoop: [NSRunLoop mainRunLoop] forMode: NSDefaultRunLoopMode]; } #pragma mark executes this method once every screen refresh (close to 60 times per second) -(void)step{// Define a variable to record the number of times executed static int s=0; // Execute 6 times per second if (++s%10==0) {UIImage *image=_images[_index]; _layer.contents=(id)image.CGImage; _index=(_index+1)%IMAGE_COUNT; } } @endCopy the code

Operation effect:

Review images

Note: the above only demonstrates the frame-by-frame animation process. In fact, combining other animation types can make the whole fish swim, so I won’t go into details here.

UIView animation encapsulation

With the previous core animation knowledge, WE believe that the development of a general animation effect should be no problem. In the beginning of the core animation, I also told you that IN fact UIView itself has corresponding encapsulation for basic animation, keyframe animation and transition animation, and it is much simpler to use in the case of no special requirements for animation details. Can say in the daily development of more than 90% of the case using UIView animation encapsulation method can be done, so after familiar with the principle of core animation or it is necessary to give you a brief introduction to the use of various kinds of UIView animation. Since the previous core animation content has been introduced in detail, learning UIView encapsulation method is a piece of cake, here for some details will not be repeated.

Based on the animation

The basic animation section corresponds to the previous basic animation demonstration, demonstrating the process of falling leaves on the click screen to the mouse click position. Notice from the implicit animation that WE’ve been talking about you can actually animate a non-root layer without having to animate it using UIView, so instead of putting it on a layer it’s putting it on a UIImageView.

The following code demonstrates the process of implementing animation control with block and static methods:

// // UIView implementation Basic Animation // Animation // // Created by Kenshin Cui on 14-3-22. // Copyright (C) 2014 Kenshin Cui. All Rights reserved. // #import "KCMainViewController.h" @interface KCMainViewController (){ UIImageView *_imageView; } @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; UIImage *backgroundImage=[UIImage imageNamed:@"background.jpg"]; self.view.backgroundColor=[UIColor colorWithPatternImage:backgroundImage]; _imageView=[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"petal. PNG "]]; _imageView.center=CGPointMake(50, 150); [self.view addSubview:_imageView]; } # create view -(void)touch began :(NSSet *)touches :(UIEvent *) view {touch * touches. AnyObject; CGPoint location= [touch locationInView:self.view]; // Method 1: Duration: duration: delay: options: animation Settings, duration: duration: delay: options: animation Settings, Such as automatic recovery, uniform motion, such as the completion: animation complete callback methods * / / / [UIView animateWithDuration: 5.0 delay: 0 options: UIViewAnimationOptionCurveLinear animations:^{ // _imageView.center=location; // } completion:^(BOOL finished) { // NSLog(@"Animation end."); // }]; UIView beginAnimations:@"KCBasicAnimation" context:nil]; // Method 2: static method // Start animations [UIView beginAnimations:@"KCBasicAnimation" context:nil]; [UIView setAnimationDuration: 5.0]; / / [UIView setAnimationDelay: 1.0]; / / set delay / / [UIView setAnimationRepeatAutoreverses: NO]; / / whether the reply / / [UIView setAnimationRepeatCount: 10]. //[UIView setAnimationStartDate:(NSDate *)]; / / set the animation starts running time / / [UIView setAnimationDelegate: self]. / / agent/set / [UIView setAnimationWillStartSelector: (SEL)]; / / set up animation began to exercise the execution method of / / [UIView setAnimationDidStopSelector: (SEL)]; _imageView.center=location; // Start animations [UIView commitAnimations]; } @endCopy the code

Added – Spring animation effect

Due to the use of elastic animation in iOS development is very common, so in iOS7 Apple official directly provides a method for elastic animation development, the following simple demonstration:

// // UIView Implementation Basic Animation -- Elastic Animation // Animation // // Created by Kenshin Cui on 14-3-22. // Copyright (C) 2014 Kenshin Cui. All rights reserved. // #import "KCMainViewController.h" @interface KCMainViewController (){ UIImageView *_imageView; } @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; _imageView=[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"ball.png"]]; _imageView.center=CGPointMake(160, 50); [self.view addSubview:_imageView]; } # create view -(void)touch began :(NSSet *)touches :(UIEvent *) view {touch * touches. AnyObject; CGPoint location= [touch locationInView:self.view]; /* Create elastic damping; damping, range 0-1, the closer the damping is to 0, Elastic effect more apparent velocity: the speed of elastic reset * / [UIView animateWithDuration: 5.0 delay: 0 usingSpringWithDamping: initialSpringVelocity 0.1:1.0  options:UIViewAnimationOptionCurveLinear animations:^{ _imageView.center=location; //CGPointMake(160, 284);  } completion:nil]; } @endCopy the code

Operation effect:

Review images

Add — animation Settings parameters

There is an option parameter in the animation method, UIViewAnimationOptions, which is an enumerated type. Animation parameters fall into three categories, which can be used in combination:

1. General animation property Settings (multiple Settings can be selected at the same time)

UIViewAnimationOptionLayoutSubviews: animation process ensure child views following the movement.

UIViewAnimationOptionAllowUserInteraction: allow user interaction in the process of animation.

UIViewAnimationOptionBeginFromCurrentState: all views from the current state began to run.

UIViewAnimationOptionRepeat: repeat the animation.

UIViewAnimationOptionAutoreverse: after running animation to the end point is still in animation way back to the initial point.

Set time UIViewAnimationOptionOverrideInheritedDuration: ignore nested animation.

UIViewAnimationOptionOverrideInheritedCurve: ignore nested animation speed setting.

UIViewAnimationOptionAllowAnimatedContent: redraw the view in the process of animation (note that only applies to ferry animation).

UIViewAnimationOptionShowHideTransitionViews: View switch directly to hide old view, according to a new view, rather than remove the old view from the parent view (only applicable to ferry animation) UIViewAnimationOptionOverrideInheritedOptions: don’t inherit the parent animation set or animation types.

2. Animation speed control (select one of these Settings)

UIViewAnimationOptionCurveEaseInOut: animation, first slowly, then gradually accelerated.

UIViewAnimationOptionCurveEaseIn: animation gradually slow down.

UIViewAnimationOptionCurveEaseOut: animation gradually accelerated.

Uniform execution UIViewAnimationOptionCurveLinear: animation, the default value.

3. Transition type (only applicable to transition animation Settings, you can choose one of them to set, basic animation, keyframe animation do not need to set)

UIViewAnimationOptionTransitionNone: no transitions animation effects.

UIViewAnimationOptionTransitionFlipFromLeft: from the left side of the rollover effect.

UIViewAnimationOptionTransitionFlipFromRight: from the right side of the rollover effect.

UIViewAnimationOptionTransitionCurlUp: flip back animation transition effects.

UIViewAnimationOptionTransitionCurlDown: flip forward animation transition effects.

UIViewAnimationOptionTransitionCrossDissolve: old view solution shows the effect of a new view.

UIViewAnimationOptionTransitionFlipFromTop: flip down from above effect.

UIViewAnimationOptionTransitionFlipFromBottom: from the bottom of the reverse effect.

Keyframe animation

Since iOS7, UIView animation encapsulates keyframe animation. Now let’s see how to use UIView encapsulation method to control keyframe animation, which implements the control of the previous keyframe animation for falling flowers.

// // UIView Keyframe animation // UIViewAnimation // // Created by Kenshin Cui on 14-3-22. // Copyright (C) 2014 Kenshin Cui. All rights reserved. // #import "KCMainViewController.h" @interface KCMainViewController (){ UIImageView *_imageView; } @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; UIImage *backgroundImage=[UIImage imageNamed:@"background.jpg"]; self.view.backgroundColor=[UIColor colorWithPatternImage:backgroundImage]; _imageView=[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"petal. PNG "]]; _imageView.center=CGPointMake(50, 150); [self.view addSubview:_imageView]; } -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ //UITouch *touch=touches.anyObject; //CGPoint location= [touch locationInView:self.view]; / * keyframe animation options: * / [UIView animateKeyframesWithDuration: 5.0 delay: 0 options: UIViewAnimationOptionCurveLinear| UIViewAnimationOptionCurveLinear animations:^{ // Second keyframe (to be exact, the first keyframe is the starting position) : the first keyframe starts from 0 seconds and lasts 50% of the time, Or 5.0 * 0.5 = 2.5 seconds [UIView addKeyframeWithRelativeStartTime: relativeDuration 0.0:0.5 animations: ^ { _imageView. Center = CGPointMake (80.0, 220.0);}]; // Keyframe 3, starting from 0.5*5.0 seconds, For 5.0 * 0.25 = 1.25 seconds [UIView addKeyframeWithRelativeStartTime: relativeDuration 0.5:0.25 animations: ^ { _imageview.center =CGPointMake(45.0, 300.0);}]; Starting at 0.75*5.0 seconds, Hold the required 5.0 * 0.25 = 1.25 seconds [UIView addKeyframeWithRelativeStartTime: relativeDuration 0.75:0.25 animations: ^ { } completion:^(BOOL finished) {NSLog(@"Animation End.");}]; } @endCopy the code

Add — animation Settings parameters

For key frame animation parameters setting options, there are also some animation UIViewKeyframeAnimationOptions type, and the above animation parameters setting some basic difference, there are two types of key frame animation set parameters, can use a combination of:

1. General animation property Settings (multiple Settings can be selected at the same time)

UIViewAnimationOptionLayoutSubviews: animation process ensure child views following the movement.

UIViewAnimationOptionAllowUserInteraction: allow user interaction in the process of animation.

UIViewAnimationOptionBeginFromCurrentState: all views from the current state began to run.

UIViewAnimationOptionRepeat: repeat the animation.

UIViewAnimationOptionAutoreverse: after running animation to the end point is still in animation way back to the initial point.

Set time UIViewAnimationOptionOverrideInheritedDuration: ignore nested animation. UIViewAnimationOptionOverrideInheritedOptions: no father animation set or animation types.

2. Animation mode setting (corresponding to the previous keyframe animation mode one by one, you can choose one of them to set)

UIViewKeyframeAnimationOptionCalculationModeLinear: continuous operation mode.

UIViewKeyframeAnimationOptionCalculationModeDiscrete: discrete operation mode.

Uniform UIViewKeyframeAnimationOptionCalculationModePaced: perform operation mode.

UIViewKeyframeAnimationOptionCalculationModeCubic: smooth operation mode.

UIViewKeyframeAnimationOptionCalculationModeCubicPaced: smoothly operation mode.

Note: There are two forms of keyframe animation as mentioned earlier. The above is a property value keyframe animation. Path keyframe animation is not currently supported by UIView.

Animated transitions

Starting with iOS4.0, UIView encapsulates transitions directly, which is also easy to use.

// // UIView TransitionAnimation // TransitionAnimation // // Created by Kenshin Cui on 14-3-12. // Copyright (c) 2014 Kenshin Cui. All  rights reserved. // #import "KCMainViewController.h" #define IMAGE_COUNT 5 @interface KCMainViewController (){ UIImageView *_imageView; int _currentIndex; } @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; _imageView=[[UIImageView alloc]init]; _imageView.frame=[UIScreen mainScreen].applicationFrame; _imageView.contentMode=UIViewContentModeScaleAspectFit; _imageView.image=[UIImage imageNamed:@"0.jpg"]; // Default image [self.view addSubview:_imageView]; // Add gesture UISwipeGestureRecognizer *leftSwipeGesture=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(leftSwipe:)]; leftSwipeGesture.direction=UISwipeGestureRecognizerDirectionLeft; [self.view addGestureRecognizer:leftSwipeGesture]; UISwipeGestureRecognizer *rightSwipeGesture=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(rightSwipe:)]; rightSwipeGesture.direction=UISwipeGestureRecognizerDirectionRight; [self.view addGestureRecognizer:rightSwipeGesture]; } #pragma mark -(void)leftSwipe:(UISwipeGestureRecognizer *) Gesture {[self transitionAnimation:YES]; } #pragma Mark -(void)rightSwipe:(UISwipeGestureRecognizer *) Gesture {[self transitionAnimation:NO]; } #pragma mark -(void)transitionAnimation:(BOOL)isNext{UIViewAnimationOptions option; if (isNext) { option=UIViewAnimationOptionCurveLinear|UIViewAnimationOptionTransitionFlipFromRight; }else{ option=UIViewAnimationOptionCurveLinear|UIViewAnimationOptionTransitionFlipFromLeft; } [UIView transitionWithView:_imageView Duration :1.0 options:option animations:^{_imageview.image =[self getImage:isNext]; } completion:nil]; } #pragma mark gets the current image -(UIImage *)getImage:(BOOL)isNext{if (isNext) {_currentIndex=(_currentIndex+1)%IMAGE_COUNT; }else{ _currentIndex=(_currentIndex-1+IMAGE_COUNT)%IMAGE_COUNT; } NSString *imageName=[NSString stringWithFormat:@"%i.jpg",_currentIndex]; return [UIImage imageNamed:imageName]; } @endCopy the code

In the transition animation demo above, there is actually only one view, UIImageView, that does the transition, and each transition is done by switching the contents of the UIImageView. If you have two completely different views and each view has a complex layout, Now to transition between these two views you can use + (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion _0 NS_AVAILABLE_IOS (4) methods for transitions between two views, it’s important to note that by default will transferred out of view from the parent view removed, turn to add back after, can pass UIViewAnimationOptionShowHideTransitionViews parameter Settings, When this parameter is set, outgoing views are hidden (not removed) and displayed later.

Note: The parameters of transition animation are exactly the same as those of basic animation; Instead of using a transition animation directly, using the DECORator method of UIView has less animation because you can’t use the private API directly.