When exactly do implicit animations take place in

2019-01-10 21:16发布

问题:

Everyone and every book claims that there are implicit animations happening in CALayer. However, every time I wanted to verify that so far, I end up with a hard-snap to the set value. No animation at all.

Here's an example in a project where nothing else is happening. All I do is create a view, then get it's CALayer instance and do something that should be implicitly animated.

[theLayer setValue:[NSNumber numberWithFloat:M_PI * 1.1] forKeyPath:@"transform.rotation.z"];

Another one:

CGRect currentBounds = theLayer.bounds;
currentBounds.size.width += 120.f;
[self.animatedLayer setBounds:currentBounds];

The view contains some stuff of course so I can see the change. I see the visual change, but as a hard snap. No animation at all.

So either all those books are wrong and have old Mac OS X knowledge in mind when writing about Core Animation and implicit animations, or I'm doing something wrong. Can anyone provide an working example that demonstrates implicit animations on the iPhone?

回答1:

UIKit disables implicit animations. To be more specific, a CALayer associated with a UIView will never implicitly animate. CALayers that you create yourself and that are not associated with a UIView will buy into the normal implicit animation machinery.

If you're interested in how this works, implicit animations happen after the normal -actionForKey: lookup. If there's a CAAction for a given property, it's used. Otherwise, the implicit animation is used. In the case of a CALayer associated with a UIView, UIView implements the -actionForLayer:forKey: delegate method, and when not in a UIView animation block it always returns [NSNull null] to signify that the action lookup should stop here. This prevents implicit animations from working. Inside of a UIView animation block, it constructs its own action to represent the current UIView animation settings. Again, this prevents implicit animations.

If you need to animate CALayer properties that UIView won't do for you, you can use an explicit CAAnimation subclass (such as CABasicAnimation).



回答2:

Old post, but link below points to a section in the Core Animation Programming Guide that helps shed some more light on what Kevin Ballard was saying. There really needs to be a blatant note that mentions that in order to animate a UIView's underlying layer properties you need to ensure that you set the layer's delegate to an instance that will adopt the "actionForLayer:ForKey:" method and return nil. It's been found that you can also set the delegate to an instance that doesn't adopt this method and it still allows implicit animations, but this is a sloppy and confusing practice.

Core Animation - Layer Actions - Defined Search Pattern for Action Keys



回答3:

Keep in mind that sublayers of a UIView's primary layer do not normally have the UIView as their delegate. Therefore, they participate in implicit animation unless you explicitly block this, even if you haven't provided a delegate to return a nil action in response to actionForLayer:forKey:.

So, one simple way to get implicit animation in a generic view is simply to add a sublayer that covers the primary layer.

Matt Neuberg's book Programming iOS 5 (currently in beta on Safari Books Online) explains this topic very lucidly.



回答4:

It's exactly correct of Kevin Ballard's answer. I want to provide something more here.

The detail information from the official document

There is a section called: Rules for Modifying Layers in iOS, and you will find

The UIView class disables layer animations by default but reenables them inside animation blocks.

Except enable the implicit in the UIView animation block. There are two another solution:

  1. Make the layer you need animation a sublayer of a view. Refer to the [answer][2]

    [2]: Implicit property animations do not work with CAReplicatorLayer? of Implicit animation fade-in is not working. I tried this, it worked as expected.

  2. assign the layer's delegate to the layer itself. The default delegate of the layer in iOS is its backing store view which implements the actionForLayer:(id)layer forKey:(NSString *)key and return [NSNull null] to disable the implicit animation of the layer.


回答5:

You could also set the layer's delegate to your own object and handle -actionForLayer:forKey:. Seems as if you get implicit animation even if the delegate doesn't implement -actionForLayer:forKey:.



回答6:

actually, you could just return nil to get the default animation of CALay.

  • (id)actionForLayer:(CALayer *)layer forKey:(NSString *)event{ return nil; }