ios 如何禁用 CALayer 隐式动画?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5833488/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 19:45:26  来源:igfitidea点击:

How to disable CALayer implicit animations?

iosanimationcalayer

提问by Esepher

It's driving me crazy! I am working on a drawing application. Let's say I am working on a UIViewcalled sheet.

这让我疯狂!我正在开发绘图应用程序。假设我正在处理一个UIView被调用的工作表。

I am adding some sublayers to this view ([sheet.layer addSublayer:...]) and then I want to draw into them. To do so I am creating a CGImageRefand putting it into the layer's contents. But it's animated and I don't want that.

我正在向这个视图 ( [sheet.layer addSublayer:...])添加一些子图层,然后我想绘制它们。为此,我正在创建一个CGImageRef并将其放入图层的contents. 但它是动画的,我不想要那样。

I tried everything:

我尝试了一切:

  • removeAnimationForKey:
  • removeAllAnimations
  • set the actions dictionary
  • using the actionlayer delegate
  • [CATransaction setDisableAnimations:YES]
  • removeAnimationForKey:
  • removeAllAnimations
  • 设置动作字典
  • 使用动作层 delegate
  • [CATransaction setDisableAnimations:YES]

It's seems correct. I don't understand why this layer is still animated ;_;
Am I doing something wrong? Is there a secret way?

好像是对的。我不明白为什么这个层仍然是动画的;_;
难道我做错了什么?有什么秘诀吗?

回答by Olivier Tabone

You have to explicitly disable animations by wrapping your code in a CATransaction

您必须通过将代码包装在 CATransaction 中来显式禁用动画

[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue
                 forKey:kCATransactionDisableActions];
layer.content = someImageRef;
[CATransaction commit];

回答by Suragch

Swift

迅速

CATransaction.begin()
CATransaction.setDisableActions(true)

// change layer properties that you don't want to animate

CATransaction.commit()

回答by zneak

As of Mac OS X 10.6 and iOS 3, CATransactionalso has a setDisableActionsmethod that sets the value for key kCATransactionDisableActions.

从 Mac OS X 10.6 和 iOS 3 开始,CATransaction也有一个setDisableActions设置 key 值的方法kCATransactionDisableActions

[CATransaction begin];
[CATransaction setDisableActions:YES];

layer.content = someImageRef;

[CATransaction commit];

In Swift, I like to use this extension method:

在 Swift 中,我喜欢使用这种扩展方法:

extension CATransaction {
    class func withDisabledActions<T>(_ body: () throws -> T) rethrows -> T {
        CATransaction.begin()
        CATransaction.setDisableActions(true)
        defer {
            CATransaction.commit()
        }
        return try body()
    }
}

You can then use it like this:

然后你可以像这样使用它:

CATransaction.withDisabledActions {
    // your stuff here
}

回答by holodnyalex

Another way:

其它的办法:

  1. You should disable default animation of your sheet.layer, which is called implicitly when adding sublayer.

  2. You should also content-animation of each sublayer. Of course, you can use "kCATransactionDisableActions" of CATransaction each time you set sublayer.content. But, you can disable this animation once, when you are creating your sublayer.

  1. 您应该禁用 sheet.layer 的默认动画,它在添加子图层时被隐式调用。

  2. 您还应该对每个子层进行内容动画处理。当然,每次设置 sublayer.content 时都可以使用 CATransaction 的“kCATransactionDisableActions”。但是,您可以在创建子图层时禁用一次此动画。



Here is code:

这是代码:

// disable animation of container
sheet.layer.actions = [NSDictionary dictionaryWithObject:[NSNull null] 
                                                  forKey:@"sublayers"];

// disable animation of each sublayer
sublayer.layer.actions = [NSDictionary dictionaryWithObject:[NSNull null] 
                                                     forKey:@"content"];

// maybe, you'll also have to disable "onOrderIn"-action of each sublayer.       

回答by Skaal

Swift 4 extension :

斯威夫特 4 扩展:

extension CATransaction {

    static func disableAnimations(_ completion: () -> Void) {
        CATransaction.begin()
        CATransaction.setDisableActions(true)
        completion()
        CATransaction.commit()
    }

}

Usage :

用法 :

    CATransaction.disableAnimations {
        // things you don't want to animate
    }

回答by Oleg Barinov

Layer extension:

层扩展:

extension CALayer {    
    var areAnimationsEnabled: Bool {
        get { delegate == nil }
        set { delegate = newValue ? nil : CALayerAnimationsDisablingDelegate.shared }
    }
}

private class CALayerAnimationsDisablingDelegate: NSObject, CALayerDelegate {
    static let shared = CALayerAnimationsDisablingDelegate()
    private let null = NSNull()

    func action(for layer: CALayer, forKey event: String) -> CAAction? {
        null
    }
}

Usage:

用法:

anyLayer.areAnimationsEnabled = false

回答by Ryan Francesconi

This is an old question but the problem remains. Sometimes you don't want the animations that CALayer forces on you. I wasn't happy with the transaction based approach as I just wanted to turn these actions off. For good. Here's a Swift 4 solution to subclass CALayer to allow a choice whether to allow any action or globally disable them. You can also create CAShapeLayer, CATextLayer subclasses with the same contents:

这是一个老问题,但问题仍然存在。有时您不想要 CALayer 强加给您的动画。我对基于事务的方法不满意,因为我只想关闭这些操作。好的。这是一个 Swift 4 解决方案,用于继承 CALayer 以允许选择是允许任何操作还是全局禁用它们。您还可以创建具有相同内容的 CAShapeLayer、CATextLayer 子类:

public class ActionCALayer: CALayer {
    public var allowActions: Bool = false

    override public func action(forKey event: String) -> CAAction? {
        return allowActions ? super.action(forKey: event) : nil
    }
}

回答by user4806509

Swift 2

斯威夫特 2

I was able to disable all animations as follows, where myViewis the view you are working with:

我能够按如下方式禁用所有动画,myView您正在使用的视图在哪里:

myView.layer.sublayers?.forEach { 
myView.layer.sublayers?.forEach { 
/**
 * Disable Implicit animation
 * EXAMPLE: disableAnim{view.layer?.position = 20}//Default animation is now disabled
 */
func disableAnim(_ closure:()->Void){
    CATransaction.begin()
    CATransaction.setDisableActions(true)
    closure()
    CATransaction.commit()
}
.removeFromSuperlayer() }
.removeAllAnimations() }

And as a side note, removing all layers:

作为旁注,删除所有图层:

yourCALayer.actions = [NSDictionary dictionaryWithObject:[NSNull null] forKey:@"position"];

回答by eonist

Reusable global code:

可重用的全局代码:

for (CALayer *iterationLayer in self.layer.sublayers ) {
    iterationLayer.actions = [NSDictionary dictionaryWithObject:[NSNull null] forKey:@"position"];
    //or for multiple keys at once
    NSNull *nop = [NSNull null];
    iterationLayer.actions = [NSDictionary dictionaryWithObjects:@[nop,nop] forKeys:@[@"position",@"contents"]];
}

Add this code anywhere in your code (Globally scoped)

将此代码添加到您的代码中的任何位置(全局范围)

回答by Ol Sen

beforeadding the layer to your view with i.e. [self.layer addSublayer:yourCALayer]and also after its already added you can disable specific animated propertys of your CALayer by overwriting the animation key. The key you set to NULL is named after the property, here shown like its done for the layer.position = CGPoint(x,y);

使用 ie 将图层添加到您的视图之前[self.layer addSublayer:yourCALayer]以及在它已经添加之后,您可以通过覆盖动画键来禁用 CALayer 的特定动画属性。您设置为 NULL 的键以属性命名,此处显示为layer.position = CGPoint(x,y);

##代码##

Because the actionsproperty is an NSDictionary which does not allow storing of nilyou set it explicit to an NULL object with [NSNull null], which is the same as (id)kCFNullYou can do this for all sublayers by iterating thru all sublayers of the views layer with...

因为该actions属性是一个 NSDictionary,它不允许存储nil您将其显式设置为一个 NULL 对象[NSNull null],这与(id)kCFNull您可以通过遍历视图层的所有子层对所有子层执行此操作相同...

##代码##