Подтвердить что ты не робот

Как отключить неявные анимации CALayer?

Это сводит меня с ума! Я работаю над графическим приложением. Скажем, я работаю над таблицей UIView.

Я добавляю некоторые подслои к этому представлению ([sheet.layer addSublayer:...]), а затем я хочу рисовать их. Для этого я создаю CGImageRef и помещаю его в слой contents. Но он оживился, и я не хочу этого.

Я пробовал все:

  • removeAnimationForKey:
  • removeAllAnimations
  • установить словарь действий
  • с помощью actionlayer delegate
  • [CATransaction setDisableAnimations:YES]

Кажется правильным. Я не понимаю, почему этот слой все еще анимирован; _;
Я делаю что-то неправильно? Есть ли секретный способ?

4b9b3361

Ответ 1

Вы должны явно отключить анимацию, обернув свой код в CATransaction

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

Ответ 2

Swift

CATransaction.begin()
CATransaction.setDisableActions(true)

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

CATransaction.commit()

Ответ 3

Как и в 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
}

Ответ 4

Другой способ:

  • Вы должны отключить анимацию по умолчанию вашего листового слоя, который неявно называется добавлением подуровня.

  • Вы также должны использовать контент-анимацию каждого подуровня. Конечно, вы можете использовать "kCATransactionDisableActions" CATransaction каждый раз, когда вы устанавливаете sublayer.content. Но вы можете отключить эту анимацию один раз, когда вы создаете подуровень.


Вот код:

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

Ответ 5

Swift 2

Мне удалось отключить все анимации следующим образом, где myView - это вид, с которым вы работаете:

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

И как примечание, удалив все слои:

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

Ответ 6

Многоразовый глобальный код:

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

Добавьте этот код в любом месте вашего кода (в глобальном масштабе)

Ответ 7

Расширение 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
    }

Ответ 8

перед добавлением слоя к вашему виду с помощью [self.layer addSublayer:yourCALayer] а также после того, как он уже добавлен, вы можете отключить определенные анимированные свойства вашего CALayer, переписав ключ анимации. Ключ, который вы установили в NULL, назван в честь свойства, здесь показано, как это сделано для layer.position = CGPoint(x,y);

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

Поскольку свойство actions - это NSDictionary, который не позволяет хранить nil вы устанавливаете его явным образом для объекта NULL с помощью [NSNull 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"]];
}

Ответ 9

Это старый вопрос, но проблема остается. Иногда вам не нужны анимации, которые навязывает вам 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
    }
}

Ответ 10

Я полностью согласен с Райаном. Его ответ - для 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)
}