An explicit animation

Source: Internet
Author: User
Tags abstract

If you want to make things go well, only by yourself--Charles Guillaume

The previous chapter describes the concept of implicit animation. Implicit animation is a direct way to create a dynamic user interface on the iOS platform and is the foundation of the Uikit animation mechanism, but it does not cover all animation types. In this chapter, we're going to look at explicit animations that can specify custom animations for some properties, or create non-linear animations, such as moving along any curve. Property Animation

First, let's explore the attribute animation. A property animation acts on a single property of a layer, specifying one of its target values, or a series of values that will be animated. There are two types of property animations: Basic and Keyframe. Basic Animation

Animation is actually a period of time changes occur, the simplest form is to change from one value to another, which is the most important function of cabasicanimation. Cabasicanimation is a subclass of Capropertyanimation, and Capropertyanimation's parent is caanimation,caanimation and core Animation the abstract base class for all animation types. As an abstract class, the caanimation itself does not do much work, it provides a timer function (see Chapter Tenth "Buffering"), a delegate (for feedback animation state), and a removedoncompletion, Used to identify whether the animation should be automatically released after the end (default yes, to prevent memory leaks). Caanimation also implements some protocols, including Caaction (allowing caanimation subclasses to provide layer behavior), and camediatiming (nineth "Layer time" will be explained in detail).

Capropertyanimation by specifying the keypath of an animation for a single property, Caanimation is typically applied to a specified calayer, so this refers to the keypath of a layer. It's actually a critical path (some point notation can point to any nested object in a hierarchical relationship), rather than just the name of a property, because it means that the animation can be used not only for the properties of the layer itself, but also for the properties of its child members, or even some virtual properties (explained later in detail).

Cabasicanimation inherits from Capropertyanimation and adds the following properties:

ID fromvalue ID 
tovalue 
ID byvalue

You can get a good explanation from naming: Fromvalue represents the value of the property before the animation starts, Tovalue represents the value after the animation is finished, and byvalue represents the value that was changed during the animation execution.

By combining these three properties there can be many ways to specify the process of an animation. They are defined as ID types instead of specific types because property animations can be used as attribute types for many different kinds, including numeric types, vectors, transformation matrices, and even colors or pictures.

ID types can contain arbitrary objects derived from nsobject, but sometimes you want to animate some types of attributes that do not inherit directly from NSObject, which means you need to encapsulate them with an object, or strongly convert them to an object, Just like some of the core foundation types that are similar to some features and Objective-c objects. But how to convert from a specific data type to an ID may not seem obvious, as shown in table 8.1 for some common examples.

Table 8.1 Some types of conversions for capropertyanimation

Type Object Type Code Example
cgfloat nsnumber id obj = @ (float);
cgpoint nsvalue id obj = [nsvalue valuewithcgpoint:point);
cgsize nsvalue id obj = [nsvalue valuewithcgsize:size);
cgrect nsvalue id obj = [nsvalue valuewithcgrect:rect);
catransform3d nsvalue id obj = [nsvalue valuewithcatransform3d:transform);
cgimageref ID id obj = (__bridge id) imageref;
cgcolorref ID id obj = (__bridge id) colorref;

The Fromvalue,tovalue and Byvalue properties can be grouped in many ways, but to prevent conflicts, you cannot specify these three values at once. For example, if the specified fromvalue equals 2,tovalue equals 4,byvalue equals 3, then the core animation does not know whether the result is 4 (tovalue) or 5 (Fromvalue + byvalue). Their usage is well described in the Cabasicanimation header, so there is no repetition here. In general, you just need to specify Tovalue or Byvalue, and the rest of the values can be automatically computed from the context.

For example: We modify the animation of the color gradient in chapter seventh, replacing the previous implicit animation with an explicit cabasicanimation, as shown in Listing 8.1.

Listing 8.1 uses Cabasicanimation to set the layer background color

@interface Viewcontroller () @property (nonatomic, weak) Iboutlet UIView *layerview;

@property (nonatomic, strong) Iboutlet Calayer *colorlayer;
    @end @implementation Viewcontroller-(void) viewdidload {[Super viewdidload];
    Create Sublayer self.colorlayer = [Calayer layer];
    Self.colorLayer.frame = CGRectMake (50.0f, 50.0f, 100.0f, 100.0f); Self.colorLayer.backgroundColor = [Uicolor Bluecolor].
    Cgcolor;
Add it to our view [Self.layerView.layer AddSublayer:self.colorLayer];
    }-(Ibaction) ChangeColor {//create a new random color cgfloat red = Arc4random ()/(cgfloat) Int_max;
    CGFloat green = Arc4random ()/(cgfloat) Int_max;
    CGFloat blue = Arc4random ()/(cgfloat) Int_max;
    Uicolor *color = [Uicolor colorwithred:red green:green blue:blue alpha:1.0];
    Create a basic animation cabasicanimation *animation = [cabasicanimation animation];
    Animation.keypath = @ "BackgroundColor"; Animation.tovalue = (__bridge id) color. Cgcolor;
    Apply animation to layer [Self.colorlayer addanimation:animation forkey:nil]; } @end

Run the program, the result is a bit passable, click on the button, you can make the layer animation transition to a new color, but immediately after the animation back to the original value.

This is because the animation does not change the layer's model, but only renders it (seventh chapter). Once the animation is finished and removed from the layer, the layer immediately reverts to the previously defined appearance state. We have never changed the BackgroundColor property, so the layer returns to the original color.

When using implicit animation, in fact it is implemented in the example cabasicanimation (recall the seventh chapter, we-actionforlayer:forkey: The result of the method of the delegate printing is cabasicanimation). But in that case, we turn on the animation by setting the properties. We do the same thing here, but we don't set any property values (that's why we immediately change back to the original state).

The behavior of setting the animation to a layer (and then starting the animation by changing the value of the property) is the easiest way to synchronize the property values and animation state so far, assuming that for some reason we can't do this (usually because the uiview associated with the layer can't animate), Then there are two ways to update property values: Before the animation starts or after the animation finishes.

Changing the value of a property before the animation is the easiest way to do it, but that means we can't use fromvalue so well, and manually set the Fromvalue to the current value of the layer.

Then you can solve the problem by inserting the following code before the animation is created.

Animation.fromvalue = (__bridge id) self.colorLayer.backgroundColor; 
Self.colorLayer.backgroundColor = color. Cgcolor;

This is really doable, but there are still some problems, and if there's an animation going on here, we need to get fromvalue from the rendering layer instead of the model layer. In addition, because the layers here are not uiview associated layers, we need to disable the implicit animation behavior with catransaction, otherwise the default layer behavior interferes with our explicit animation (in fact, explicit animation usually overrides implicit animation, but it is not mentioned in the article. So it's best to do it for safety.

The updated code is as follows:

Calayer *layer = self.colorLayer.presentationLayer?:
Self.colorlayer;
 Animation.fromvalue = (__bridge id) layer.backgroundcolor;
[Catransaction begin];
[Catransaction Setdisableactions:yes];
Self.colorLayer.backgroundColor = color. Cgcolor;
[Catransaction commit];

If you add these to each animation, the code will look very bloated. Luckily, we can set these automatically from the cabasicanimation. You can then create a reusable code. Listing 8.2 Modifies the previous example by using a function of cabasicanimation to avoid repeating bloated code every time the animation is animated.

Listing 8.2 Modifies a reusable function that immediately restores the animation to its original state

-(void) Applybasicanimation: (cabasicanimation *) animation tolayer: (Calayer *) layer {//set The From value (using pre Sentation layer if available) Animation.fromvalue = [Layer.presentationlayer?: Layer ValueForKeyPath:animation.keyPat
    h];
    Update the property in advance//note:this approach'll only work if Tovalue!= nil [catransaction begin];
    [Catransaction Setdisableactions:yes];
    [Layer SetValue:animation.toValue ForKeyPath:animation.keyPath];
    [Catransaction commit];
Apply animation to layer [layer addanimation:animation forkey:nil];
    }-(Ibaction) ChangeColor {//create a new random color cgfloat red = Arc4random ()/(cgfloat) Int_max;
    CGFloat green = Arc4random ()/(cgfloat) Int_max;
    CGFloat blue = Arc4random ()/(cgfloat) Int_max;
    Uicolor *color = [Uicolor colorwithred:red green:green blue:blue alpha:1.0];
    Create a basic animation cabasicanimation *animation = [cabasicanimation animation]; Animation.keyPath = @ "BackgroundColor"; Animation.tovalue = (__bridge id) color.
    Cgcolor;
Apply animation without snap-back [self applybasicanimation:animation toLayer:self.colorLayer]; }

This simple implementation handles animations through Tovalue rather than byvalue, but it's a big step towards a better solution. You can add it to calayer as a classification to facilitate better use.

Solving a problem that seems so simple is troublesome, but other options are more complicated. If you do not update the target attribute before the animation starts, you can only update it when the animation is completely finished or canceled. This means we need to accurately update the properties before the animation finishes, before the layer returns to its original value. So how do we find this point. caanimationdelegate

In the seventh chapter, when using implicit animation, we can detect the completion of the animation in the Catransaction completion block. However, this approach does not apply to explicit animations because there is not much association between animations and transactions.

So in order to know when an explicit animation ends, we need to use a delegate that implements the Caanimationdelegate protocol.

Caanimationdelegate is not found in any header file, but can be found in the Caanimation header file or Apple Developer documentation. In this example, we use the-animationdidstop:finished: method to update the backgroundcolor of the layer after the animation finishes.

When updating properties, we need to set a new transaction and disable the layer behavior. Otherwise, the animation will occur two times, one is because of explicit cabasicanimation, another is because of implicit animation, the specific implementation see order 8.3.

Listing 8.3 Changes the background color of the layer after the animation finishes

@implementation Viewcontroller-(void) viewdidload {[Super viewdidload];
    Create Sublayer self.colorlayer = [Calayer layer];
    Self.colorLayer.frame = CGRectMake (50.0f, 50.0f, 100.0f, 100.0f); Self.colorLayer.backgroundColor = [Uicolor Bluecolor].
    Cgcolor;
Add it to our view [Self.layerView.layer AddSublayer:self.colorLayer];
    }-(Ibaction) ChangeColor {//create a new random color cgfloat red = Arc4random ()/(cgfloat) Int_max;
    CGFloat green = Arc4random ()/(cgfloat) Int_max;
    CGFloat blue = Arc4random ()/(cgfloat) Int_max;
    Uicolor *color = [Uicolor colorwithred:red green:green blue:blue alpha:1.0];
    Create a basic animation cabasicanimation *animation = [cabasicanimation animation];
    Animation.keypath = @ "BackgroundColor"; Animation.tovalue = (__bridge id) color.
    Cgcolor;
    Animation.delegate = self;
Apply animation to layer [Self.colorlayer addanimation:animation forkey:nil]; }-(void) Animationdidstop: (CabasIcanimation *) Anim finished: (BOOL) flag {//set The BackgroundColor property to match animation Tovalue [catransact
    Ion begin];
    [Catransaction Setdisableactions:yes];
    Self.colorLayer.backgroundColor = (__bridge cgcolorref) Anim.tovalue;
[Catransaction commit]; } @end

For Caanimation, using a delegate pattern rather than a completion block poses the problem that when you have more than one animation, you cannot distinguish between the callback methods. When you create an animation in a view controller, you typically use the controller itself as a delegate (as shown in Listing 8.3), but all animations call the same callback method, so you need to determine exactly what the layer calls.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.