Implicit animation: Changes CALyer layer properties to control the animation being executed through CoreAnimation

How does the system implement implicit animation

When a CALyer property is modified, the actionForyKey method is called, passing the name of the property

2. By searching for the property name, nil or the object corresponding to the CAAction protocol will be returned. CALyer animates the current or previous value by returning the result, which is completed by CoreAnimation

The transaction

The animation doesn’t need to be turned on manually, instead it needs to be explicitly turned off, otherwise it will always be there. As we’ll see when dealing with animations, we don’t need to specify an explicit animation type, just change a property and let coreAnimation decide which animation is most appropriate.

The transaction determines the actual execution time of the animation, and the layer behavior determines the animation type. Transactions are managed by the CATransaction class and can only be processed by BEGIN or COMMIT, not by initialization.

Each layer property that can be animated is added to the top-stack transaction, and any runloop will aggregate the changed properties and execute them at 0.25s (the default transaction animation time). When we set AnimationDuration, we can control the animation time of the transaction, making it faster or slower.

If we directly change the time of the current transaction in the animation, it will cause other animations to be affected at the same time, so we only need to press in a new transaction before adjusting or changing the animation time

Catransaction.begin () copies the codeCopy the code

After the property changes

CATransaction.com MIT () copies the codeCopy the code

UIView beginAnimations and commitAnimations are also implemented internally by CATransaction, but the latest API explicitly disuses these two implicit methods after iOS13. Instead, it is recommended to use the animatewithDuration block method, where all property changes in the block function are included in the transaction, thus avoiding the risk of misoperation begin and commit.

A callback to a transaction

CATransaction provides us with a callback, which means that if we use this completion callback method, it will be called when the specified animation is complete, and you can perform the next animation operation inside the code block.

SetCompletionBlock {} // Life cycle: it will not be executed until the last transaction is committed and off the stack. There are no new transactions at the time of execution, so copy the code using the system default transaction (system default transaction time 0.25s)Copy the code

Layer Behavior (emphasis)

All of the above are based on the property changes of the layer under CALyer, not the layer associated with UIView. In the process of code debugging, I tried to animate the property changes using the LAYER of UIView, and found that during this process, the implicit animation feature I expected did not work

— What does UIView do?

Each UIView acts as a delegate to the layer it’s associated with, and provides an actionForLayer:forKey: implementation method. When UIView doesn’t animate inside the block animation, UIView returns nil for layer behavior by default, If executed inside the block animation block, returns a non-null value

You can print out this code

let outside = fivrView.action(for: fivrView.layer, forKey: "backgroundColor") print("Outside: \(outside.debugDescription)") UIView.animate(withDuration: 1) { let inside = self.fivrView.action(for: self.fivrView.layer, forKey: "backgroundColor") print("Inside: \(inside.debugDescription)") } //or UIView.beginAnimations(nil, context: nil) let inside = self.fivrView.action(for: self.fivrView.layer, forKey: "backgroundColor") print("Inside: \(inside.debugDescription)") UIView.commitAnimations() Copy the codeCopy the code

Yes, when the property changes outside of the animation block, UIview disallows implicit animation by returning nil, which is turned off by UIview, and of course you can call the following code to control whether implicit animation is disabled

Copy the code CATransaction. SetDisableActions (Bool)Copy the code

– summary

  • UIViewThe associated layer has implicit animation disabled, and the only way to animate this layer is to useUIViewAnimation functions (instead of dependenciesCATransaction), or inheritanceUIViewAnd cover-actionForLayer:forKey:Or create an explicit animation (see Chapter 8 in iOS Core Animation Advanced Tips).
  • For separate layers, we can implement layer-actionForLayer:forKey:Delegate method, or provide oneactionsDictionary to control implicit animation.

– behavior

The behavior is usually an explicit Animation object that Core Animation implicitly calls. Custom behavior is where we add the displayed animation as a property of CALyer. Here we use the actions dictionary so we can write less code.

Dynamic rendering of layers (important to understand)

When we set the properties of CALyer, we are actually defining what will happen to the layer after the animation is over, rather than directly changing the content of the layer by updating the properties. Understanding this is mainly about understanding the meaning of the word “change” in the layer mechanism. The layers need to animate changes instead of applying attributes directly to the layers.

When you set the properties of the CALayer, you actually define the model of how the layer will be displayed after the current transaction has ended. The Core Animation acts as a controller and is responsible for constantly updating the on-screen state of the view’s properties based on layer behavior and transaction Settings.

If the animation time exceeds the screen refresh time, coreAnimation needs to reorganize the layers on the screen and record the display value of each layer property on the screen, also known as the rendering layer. The rendering layer is a separate layer that can be obtained through the presentationLayer. The rendering layer is actually a copy of the model layer, but its property values represent what it looks like at any given time. You can get its values to get the actual values that are displayed on the screen.

The rendering layer is created when the layer is first submitted (when it is first displayed on the screen). In most cases, we don’t need to access the rendering layer directly.

· Quoting official pictures

· Refer to the official code ·

Use hitTest to determine if a layer has been touched

colorLayer.frame = CGRect(x: 0, y: 0, width: 100, height: 100) colorLayer.position = CGPoint(x: self.view.bounds.size.width / 2, y: self.view.bounds.size.height / 2) colorLayer.backgroundColor = UIColor.red.cgColor view.layer.addSublayer(colorLayer) override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { for touch in touches { let point = touch.location(in: self.view) if ((self.colorLayer.presentation()?.hitTest(point)) ! = nil) { let red = arc4random() / UInt32(INT_MAX) let green = arc4random() / UInt32(INT_MAX) let blue = arc4random() / UInt32(INT_MAX) self.colorLayer.backgroundColor = UIColor(red: CGFloat(red), green: CGFloat(green), blue: CGFloat(blue), alpha: 1).cgColor }else { CATransaction.begin() CATransaction.setAnimationDuration(4) self.colorLayer.position = point CATransaction.com MIT ()}}} Copy the codeCopy the code

– induction

Based on the above, we can draw a clear conclusion:

The attribute value feature of the rendering layer is suitable for handling synchronous animation and gesture following

We can get it using the presentationLayer, and when we get it it’s actually a copy of the original model layer

Using the rendering layer as a reference in the interactive layer is accurate for the user

Its relationship to the model layer: rendering depends on the animation track, and the model depends on the start and end of the animation

∗ ∗ ∗ finally ∗ ∗ ∗

There are many theories in this chapter, which can be summarized into four points: 1. The influence of transactions on animation 2. Layer behavior 4. Layer dynamic value rendering. In the process of learning, deliberation and exploration can also be interesting. Understanding the original design ideas of native API is very meaningful for understanding CoreAnimation.