web-dev-qa-db-ja.com

CALayerインプリシットアニメーションを無効にする方法は?

それは私を夢中にさせています!私は描画アプリケーションに取り組んでいます。 UIViewと呼ばれるシートで作業しているとしましょう。

このビューにサブレイヤーをいくつか追加しています([sheet.layer addSublayer:...])そして私はそれらに引き込みたいです。これを行うには、CGImageRefを作成し、それをレイヤーのcontentsに入れます。しかし、それはアニメーション化されており、私はそれを望んでいません。

私はすべてを試しました:

  • removeAnimationForKey:
  • removeAllAnimations
  • アクション辞書を設定する
  • アクションレイヤーを使用するdelegate
  • [CATransaction setDisableAnimations:YES]

正しいようです。このレイヤーがまだアニメーション化されている理由がわかりません; _;
何か間違ったことをしていますか?秘密の方法はありますか?

41
Esepher

CATransactionでコードをラップして、アニメーションを明示的に無効にする必要があります

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

スウィフト

CATransaction.begin()
CATransaction.setDisableActions(true)

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

CATransaction.commit()
35
Suragch

Mac OS X 10.6およびiOS 3以降、CATransactionには、キーsetDisableActionsの値を設定するkCATransactionDisableActionsメソッドもあります。

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

layer.content = someImageRef;

[CATransaction commit];

Swiftでは、この拡張メソッドを使用するのが好きです。

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

その後、次のように使用できます。

CATransaction.withDisabledActions {
    // your stuff here
}
15
zneak

別の方法:

  1. サブレイヤーを追加するときに暗黙的に呼び出される、sheet.layerのデフォルトアニメーションを無効にする必要があります。

  2. 各サブレイヤーのコンテンツアニメーションも必要です。もちろん、sublayer.contentを設定するたびに、CATransactionの「kCATransactionDisableActions」を使用できます。ただし、サブレイヤーを作成するときに、このアニメーションを一度無効にすることができます。


ここにコードがあります:

// 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.       
13
holodnyalex

Swift 4拡張子:

extension CATransaction {

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

}

使用法 :

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

Swift 2

次のようにすべてのアニメーションを無効にすることができました。ここで、myViewは作業しているビューです。

myView.layer.sublayers?.forEach { $0.removeAllAnimations() }

補足として、すべてのレイヤーを削除します。

myView.layer.sublayers?.forEach { $0.removeFromSuperlayer() }
1
user4806509

これは古い質問ですが、問題は残っています。場合によっては、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
    }
}
1

再利用可能なグローバルコード:

/**
 * 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()
}

このコードをコードの任意の場所に追加します(グローバルスコープ)

1
eonist

レイヤー拡張:

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

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

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

使用法:

anyLayer.areAnimationsEnabled = false
0
Oleg Barinov

私はライアンに完全に同意します。彼の答えはMacOSです。iOSの場合は、次を追加してNSNull()アクションを作成します。この質問 -[CALayer setNeedsDisplayInRect:] の暗黙的なアニメーションを無効にすることと、ヘッダーのドキュメントが私をここに導きます

// Disable the implicit animation for changes to position
override open class func defaultAction(forKey event: String) -> CAAction? {
    if event == #keyPath(position) {
        return NSNull()
    }
    return super.defaultAction(forKey: event)
}
0
GayleDDS

_[self.layer addSublayer:yourCALayer]_を使用してビューにレイヤーを追加します。また、すでに追加された後、アニメーションキーを上書きして、CALayerの特定のアニメーションプロパティを無効にすることができます。 NULLに設定したキーはプロパティにちなんで名付けられ、ここではlayer.position = CGPoint(x,y);の場合と同様に示されています

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

actionsプロパティはnilの格納を許可しないNSDictionaryであるため、_[NSNull null]_でNULLオブジェクトに明示的に設定します。これは_(id)kCFNull_と同じです。これは、ビューレイヤーのすべてのサブレイヤーを反復することで、すべてのサブレイヤーに対してこれを行うことができます...

_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"]];
}
_
0
Ol Sen