Disabling implicit animations in -[CALayer setNeedsDisplayInRect:]
You can do this by setting the actions dictionary on the layer to return [NSNull null]
as an animation for the appropriate key. For example, I use
NSDictionary *newActions = @{
@"onOrderIn": [NSNull null],
@"onOrderOut": [NSNull null],
@"sublayers": [NSNull null],
@"contents": [NSNull null],
@"bounds": [NSNull null]
};
layer.actions = newActions;
to disable fade in / out animations on insertion or change of sublayers within one of my layers, as well as changes in the size and contents of the layer. I believe the contents
key is the one you're looking for in order to prevent the crossfade on updated drawing.
Swift version:
let newActions = [
"onOrderIn": NSNull(),
"onOrderOut": NSNull(),
"sublayers": NSNull(),
"contents": NSNull(),
"bounds": NSNull(),
]
How to prevent CALayer from implicit animations?
You can wrap the change in a CATransaction
with disabled animations:
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
//change background colour
[CATransaction commit];
CATextLayer - how to disable implicit animations?
The problem is that CATransaction.disableActions()
does not do what you think it does. You need to say CATransaction.setDisableActions(true)
.
And then you can get rid of all the other stuff you're saying, as it is pointless. This code alone is sufficient to change the color without animation:
CATransaction.setDisableActions(true)
layer.foregroundColor = UIColor.redColor().CGColor // or whatever
(You can wrap it in a begin()
/commit()
block if you have some other reason to do so, but there is no need just in order to switch off implicit layer property animation.)
Disable CALayer mask frame change animations
Just call layer removeAllAnimations()
AFTER setting the frame.
class GradientView: UIView {
private(set) var gradientLayer: CAGradientLayer
override init(frame: CGRect) {
gradientLayer = CAGradientLayer()
super.init(frame: frame)
layer.insertSublayer(gradientLayer, at: 0)
}
required init?(coder aDecoder: NSCoder) {
fatalError("not implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
gradientLayer.frame = bounds
gradientLayer.removeAllAnimations() // remove implicit animation from frame change
}
}
How To Disable Implicit or Automatic Animations
Alright, many headaches and much wasted time later, I figured out what the heck was going on in my code. I thought I was experiencing implicit animations, but I couldn't figure out why this started happening all of the sudden.
I decided I better try to understand implicit animations, so I experimented on my own to figure out how to achieve them in a controlled situation. The reason I have never seen implicit animations happen is because I am always using UIView or one of its subclasses.
I learned that if you start with a CALayer and work strictly with the layer, all changes to many of the properties will implicitly animate.
There may be some confusion (I know there was for me) when you see that UIView's (and their posterity) all are automatically layer backed and have a CALayer property.
Never-the-less, it is evident that UIView is somehow overriding the implicit animation mechanism of its CALayer property. So if you want implicit animations, you must use CALayer's directly, not just suppose that because UIView has a CALayer property that it will behave the same.
As for the bug I was experiencing...It was perhaps the strangest one I have yet come across. Everything, no matter what I tried, was animating any changes to values without any animation code. The culprit ended up being a nested UIView animation block.
Notice the following and see if you catch the issue right off:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.2];
//animate something
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelay:.8];
[UIView setAnimationDuration:.4];
//animate something else
[UIView commitAnimations];
I failed to terminate the nested block with another [UIView commitAnimations]. It was literally leaking animation in my program. Everything was animating, even code in completely different classes. This bug is squashed...on to the next!
CATextLayer - how to disable implicit animations?
The problem is that CATransaction.disableActions()
does not do what you think it does. You need to say CATransaction.setDisableActions(true)
.
And then you can get rid of all the other stuff you're saying, as it is pointless. This code alone is sufficient to change the color without animation:
CATransaction.setDisableActions(true)
layer.foregroundColor = UIColor.redColor().CGColor // or whatever
(You can wrap it in a begin()
/commit()
block if you have some other reason to do so, but there is no need just in order to switch off implicit layer property animation.)
Disable Implicit Animation of CATextLayer.string Property
Figured it out, using the answer for this question: Disabling implicit animations in -[CALayer setNeedsDisplayInRect:]
In my particular case, to stop the changing of the CATextLayer.string
property from being animated, this code was enough:
NSDictionary *newActions = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNull null], @"contents", nil];
textLayer.actions = newActions;
[newActions release];
In other words, it seems that the contents
key disables animations on changes to the CATextLayer.string
property.
Selectively overriding CALayer implicit animations
Your subclass is going to get actionForKey:
called on it for every key, so if you return nil
, there won't be an action for that key. If you want the default animations, you should return either [super actionForKey:event]
or [CALayer defaultActionForKey:event]
.
A layer's frame
is calculated from its bounds
and position
, so if there's no animation for those two, there can't be an animation for frame
.*
What you want to do is:
[CATransaction setValue:kCFBooleanTrue
forKey:kCATransactionDisableActions]
when your layer resizes as a result of the window resizing. This will disable animation just this time (for this transaction); when you change the layer's size directly, it will still animate. I'm not sure what the correct spot to do that call is; I just tried doing it in a callback from notification that the window was resizing, but that didn't work. I'm sure it won't be too hard for you to figure out where to put it in your code.
*: In fact, the docs say:
Note: The frame property is not directly animatable. Instead you should animate the appropriate combination of the bounds, anchorPoint and position properties to achieve the desired result.
Related Topics
Left-Align Image and Center Text on Uibutton
Uitextview Starts at Bottom or Middle of the Text
Error When Import Zlib in iOS: Symbol(S) Not Found Collect2: Ld
Cross Directional Uiscrollviews - How to Modify the Scrolling Behaviour
Implementing Auto Layout for Views Generated Programmatically
Automatic Signing Is Unable to Resolve an Issue with the "Projectname" Target's Entitlements File
How to Make Uiimageview Automatically Resize to the Size of the Image Loaded
Read Texture Bytes with Glreadpixels
Avqueueplayer Playback Without Gap and Freeze
Can't Find Pods.Modulemap - Looking in Wrong Directory
Uicollectionview Horizontal Paging Not Centered
How to Get 1 Hour Ago from a Date in iOS Swift
Show Uipickerview Text Field Is Selected, Then Hide After Selected
iOS Steps to Create Custom Uitableviewcell with Xib File
Corelocation Heading Base on Back Camera (Augmented Reality)
Remembering Scroll Position on Uitableview