Disabling implicit animations in -[CALayer setNeed

2019-01-03 03:58发布

I've got a layer with some complex drawing code in its -drawInContext: method. I'm trying to minimize the amount of drawing I need to do, so I'm using -setNeedsDisplayInRect: to update just the changed parts. This is working splendidly. However, when the graphics system updates my layer, it's transitioning from the old to the new image using a cross-fade. I'd like it to switch over instantly.

I've tried using CATransaction to turn off actions and set the duration to zero, and neither work. Here's the code I'm using:

[CATransaction begin];
[CATransaction setDisableActions: YES];
[self setNeedsDisplayInRect: rect];
[CATransaction commit];

Is there a different method on CATransaction I should use instead (I also tried -setValue:forKey: with kCATransactionDisableActions, same result).

14条回答
Animai°情兽
2楼-- · 2019-01-03 04:24

If you ever need a very quick (but admittedly hacky) fix it might be worth just doing (Swift):

let layer = CALayer()

// set other properties
// ...

layer.speed = 999
查看更多
啃猪蹄的小仙女
3楼-- · 2019-01-03 04:25

When you change the property of a layer, CA usually creates an implicit transaction object to animate the change. If you do not want to animate the change, you can disable implicit animations by creating an explicit transaction and setting its kCATransactionDisableActions property to true.

Objective-C

[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
// change properties here without animation
[CATransaction commit];

Swift

CATransaction.begin()
CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions)
// change properties here without animation
CATransaction.commit()
查看更多
贪生不怕死
4楼-- · 2019-01-03 04:28

Found out a simpler method to disable action inside a CATransaction that internally calls setValue:forKey: for the kCATransactionDisableActions key:

[CATransaction setDisableActions:YES];

Swift:

CATransaction.setDisableActions(true)
查看更多
甜甜的少女心
5楼-- · 2019-01-03 04:28

As of iOS 7 there's a convenience method that does just this:

[UIView performWithoutAnimation:^{
    // apply changes
}];
查看更多
混吃等死
6楼-- · 2019-01-03 04:32

Here's a more efficient solution, similar to accepted answer but for Swift. For some cases it will be better than creating a transaction every time you modify the value which is a performance concern as others have mentioned e.g. common use-case of dragging the layer position around at 60fps.

// Disable implicit position animation.
layer.actions = ["position": NSNull()]      

See apple's docs for how layer actions are resolved. Implementing the delegate would skip one more level in the cascade but in my case that was too messy due to the caveat about the delegate needing to be set to the associated UIView.

Edit: Updated thanks to the commenter pointing out that NSNull conforms to CAAction.

查看更多
\"骚年 ilove
7楼-- · 2019-01-03 04:32

To disable implicit layer animations in Swift

CATransaction.setDisableActions(true)
查看更多
登录 后发表回答