The previous two articles have shown that animation content at the UIView level is sufficient for most situations, but not enough for scenarios with higher performance and greater complexity. So let’s take a look deeper into Core Animation and take a look at the building blocks of the iOS Animation world.

The main content of Core Animation can be roughly divided into two categories: Layer and Animation. Let’s look at the Animation section in order to better connect with the previous section. Below is the structure of the Animation:

CAAnimation is the basis of the whole animation, and it derives CAAnimationGroup, CATransition and CAPropertyAnimation. CAPropertyAnimation further derives the three most commonly used animation classes: CABasicAnimation, CAKeyframeAnimation, and CASpringAnimation. The CAMediaTiming protocol contains all the important properties associated with the animation timeline. CAMediaTimingFunction is responsible for the time line in and out of the effect processing. The CAAnimationDelegate acts as a proxy for all animations.

Are you ready? Let’s get animated together.

CABasicAnimation

CABasicAnimation is the most frequently used basic animation. It implements animation by changing various basic properties in CALayer. But there are a lot more properties that you can animate than the UIView level. In addition to position, size, rotation Angle, etc., you can also set the border, shadow, host map.

For example, the simplest position change animation, we don’t need to set the state in viewWillAppear, we just add the code in viewDidAppear:

override func viewDidAppear(_ animated: Bool) {
    ...
    let flyRight = CABasicAnimation(keyPath: "position.x" )
    flyRight.fromValue = -view.bounds.size.width / 2
    flyRight.toValue = view.bounds.size.width / 2
    flyRight.duration = 0.5
    userAvator?.layer.add(flyRight, forKey: nil)
}

The effect is as follows:

Of course we can set the state as before and animate it:

override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) userAvator? .center.x = -view.bounds.size.width / 2 } override func viewDidAppear(_ animated: Bool) { ... let flyRight = CABasicAnimation(keyPath: "Position.x") flyright.toValue = view.bounds.size.width / 2 Flyright.duration = 0.5 userAvator? .layer.add(flyRight, forKey: nil) }

But at this point you will notice that the userAvator does not appear on the screen after the introduction of the animation. As mentioned earlier, what we see in the animation process is not the Layer Tree but the instantaneous value represented by the Presentation Tree, which is rendered by the private Render Tree. So we can see that the Presentation Tree is just animating, and the state of the object itself has not actually changed, and the userAvator is still outside the view in its preset state. To solve this problem, more granular animation control is needed.

CAMediaTiming, CAMediaTiming function for more accurate control.

CAMediaTiming as a protocol is mainly responsible for the portrayal of the animation timeline, mainly contains the following properties:

  1. BeginTime: Start time of the animation

  2. TimeOffset: The offset of the time the animation is played

  3. RepeatCount: The number of times the animation loops

  4. RepeatDuration Duration of the animation loop

  5. Duration: Animation duration

  6. Speed: The step size of the animation. The default value is 1. Can achieve fast or slow playback effect

  7. Autoreverses: Whether to animate a return to a previous state.

  8. FillMode Sets the state of the current object during the inactive period.

FillMode will only take effect if the animation’s isRemovedOnCompletion = false. It has four optional values:

  • KCAFillModeRemoved Default Value The layer is restored to its original state after the animation is over.

  • KCAFillModeBackwards immediately go to the initial state of the animation and wait for it to start.

  • KCAFillModeForwards When the animation is over, the layer will always be in the final state of the animation.

  • After kCAFillModeBoth animation is added, the layer is in the initial state of the animation before the animation ends, and the layer remains in the final state of the animation.

So, the last problem can be fixed like this:

override func viewDidAppear(_ animated: Bool) { ... FlyRight. IsRemovedOnCompletion = false flyRight. FillMode = kCAFillModeForwards / / in addition to delay setting flyRight beginTime = CACurrentMediaTime () + 0.3}

In addition to the CAMediaTiming, we can also use the CAMediaTimingFunction to set the timingFunction property in and out of the animation:

  • KCAMediaTimingFunctionLinear: linear uniform

  • KCAMediaTimingFunctionEaseIn:

  • KCAMediaTimingFunctionEaseOut: slow down

  • Slow down after kCAMediaTimingFunctionEaseInEaseOut: slow down

CASpringAnimation

As a subclass of CABasicAnimation, CASpringAnimation provides many related properties in order to better simulate the effect of damped harmonic motion:

  • The larger the damping coefficient, the easier it is to stop the animation

  • Mass: affects the inertia of the spring when the layer moves. The greater the mass, the greater the stretch and compression of the spring

  • Bounces: Elasticity coefficient. The larger the value, the larger the rebound

  • InitialVelocity: initialVelocity. Anything less than zero means that the velocity is in the opposite direction of the motion.

override func viewDidAppear(_ animated: Bool) { let flyRight = CASpringAnimation(keyPath: "Transform.scale") flyRight. FromValue = 1 flyRight. ToValue = 1.25 flyRight flyRight.stiffness = 5 flyRight.initialVelocity = 10 flyRight.duration = flyRight.settlingDuration userAvator?.layer.add(flyRight, forKey: nil) }

CAKeyframeAnimation

As with the keyframe animations in UIView, CAKeyframeAnimation is responsible for extracting the animation keyframes in the Layer. The property values in this animation include:

  • Values: All the specific values of the key frame, used to determine the action of the key frame.

  • Path: Animation path. Defaults to nil. The values in values above are ignored when manually specified.

  • KeyTimes: indicates all the nodes of the key frame. The value ranges from 0.0 to 1.0. The specific time point can be converted based on the duration.

  • TimingFunctions: Effect setting for entry and exit.

  • CalculationMode: the fitting mode of animations between key frames, which is linear by default.

  • RotationMode: Defaults to nil and determines whether the Layer is rotated tangent to the trajectory during the animation.

A simple example:

override func viewDidAppear(_ animated: Bool) { ... let flyRight = CAKeyframeAnimation(keyPath: FlyRight. Duration = 1.0 flyRight. Values = [0, -m_PI_4, -m_PI_2, -m_PI_4 * 3, -m_pi, -m_PI_4 * 5, - M_PI_2 * 3, - M_PI * 2] flyRight. KeyTimes = [,0.1 0, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8] userAvator? .layer.add(flyRight, forKey: nil) }

CATransition

As the name implies, CATransition is an animation class designed to achieve the transition effect of Layer. This animation makes the process of adding a view more natural. The specific animation properties:

  • StartProgress: The value ranges from 0.0 to 1.0, indicating that the animation starts at the moment on the duration timeline.

  • EndProgress: The same as startProgress except that it represents the end state of the animation at that point in the timeline.

  • Type: animation effect.

  • SubType: animation direction.

The value of type can be:

  • KCATransitionFade gradient

  • KCATransitionMoveIn cover

  • KCATransitionPush launch

  • KCATransitionReveal uncover

    In addition, there are the following private types:

  • Rotation of the cube

  • SuckEffect shrink animation

  • OglFlip flip

  • RippleEffect Water wave animation

  • PageCurl Uncovers the page

  • PageUnCurl Puts down the page

  • CemeraIrisHollowOpen Lens is turned on

  • CameraIrisHollowClose Lens is closed

SubType Contains the following values:

  • kCATransitionFromRight

  • kCATransitionFromLeft

  • kCATransitionFromTop

  • kCATransitionFromBottom

Sample code, with renderings:

override func viewDidAppear(_ animated: Bool) { ... Let flyRight = CATransition() flyright.duration = 1.0 flyright.type = "rippleEffect" userAvator? .layer.add(flyRight, forKey: nil) }

CAAnimationGroup

If you’re observant you’ll notice that in all of the examples above, the animation is a modification or action to a particular property. So what about doing multiple animations at once? You can also add(_ anim: CAAnimation, forKey key: String?) Function to do this by repeatedly adding animations to the Layer, but the ideal way is to use the CAAnimationGroup to combine multiple animations and add them to the Layer.

We just need to add those individual animations to the animations array, CAAnimationGroup will do the rest just fine.

Sample code and renderings are shown below:

override func viewDidAppear(_ animated: Bool) { ... let spring = CASpringAnimation(keyPath: "Transform.scale") spring.fromValue = 1 Spring.tovalue = 1.25 spring. Damping = 5 Spring.mass = 1 Spring spring.initialVelocity = 10 spring.duration = spring.settlingDuration let keyframe = CAKeyframeAnimation(keyPath: "transform.rotation" ) keyframe.duration = spring.settlingDuration keyframe.values = [0,-M_PI_4,-M_PI_2,-M_PI_4 * 3,-M_PI,-M_PI_4 * 5,-M_PI_2 * 3, - M_PI * 2] keyframe. KeyTimes = [,0.1 0, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8] let flyRight = CAAnimationGroup () flyRight. Animations  = [spring,keyframe] flyRight.duration = spring.settlingDuration userAvator?.layer.add(flyRight, forKey: nil) }

conclusion

At this point, I believe you have a general understanding of several kinds of Animation in the Core Animation framework. Of course, these animations have very familiar details to explore, such as: keyframe animation in several interpolation simulation, the reader can explore. We’ll save the Core Animation special Layer for the next section.