¿Cómo se mueve un CALayer instantáneamente (sin animación)?


80

Estoy intentando arrastrar un CALayeren una aplicación de iOS.

Tan pronto como cambio su propiedad de posición, intenta animarse a la nueva posición y parpadea por todos lados:

 layer.position = CGPointMake(x, y)

¿Cómo puedo moverme al CALayersinstante? Parece que no puedo entender la API de animación principal.


con respecto a este control de calidad extremadamente antiguo, el problema crítico hoy es el siguiente: stackoverflow.com/a/56980329/294884
Fattie

Respuestas:


168

Desea terminar su llamada de la siguiente manera:

[CATransaction begin]; 
[CATransaction setValue: (id) kCFBooleanTrue forKey: kCATransactionDisableActions];
layer.position = CGPointMake(x, y);
[CATransaction commit];

1
Eso es exactamente. Ni siquiera pensé en la transacción CAT. ¡Muchas gracias!
Mel

5
Sí, 6 años y medio después. Sigue siendo útil. : D
Fogmeister

1
iOS7 admite una nueva taquigrafía:[UIView performWithoutAnimation:<#^(void)actionsWithoutAnimation#>];
k06a

2
7 años, 7 meses y 17 días después: sigue siendo útil. ¡Gracias!
kanobius

1
pulgar hacia arriba 9 años después
nshuman

32

Extensión Swift 3:

extension CALayer {
    class func performWithoutAnimation(_ actionsWithoutAnimation: () -> Void){
        CATransaction.begin()
        CATransaction.setValue(true, forKey: kCATransactionDisableActions)
        actionsWithoutAnimation()
        CATransaction.commit()
    }
}

Uso:

CALayer.performWithoutAnimation(){
    someLayer.position = newPosition
}

1
Es útil agregar el @noescapeatributo al bloque para permitir (y dejar en claro) que selfno se necesita en el bloque
Andrew

22

También puede utilizar la función de conveniencia

[CATransaction setDisableActions:YES] 

también.

Nota: asegúrese de leer los comentarios de Yogev Shelly para comprender cualquier error que pueda ocurrir.


5
Importante, estos efectos todas CALayer por lo que desea volver a habilitar las acciones después de que haya terminado, es decir, [setDisableActions CATransaction: SI]
Yogev Shelly

Maldita sea, debería haber dicho eso. Buen ahorro. El comando desactiva las animaciones hasta que se establece en NO o hasta que el motor de animación de gráficos principal haya completado un ciclo de ejecución. No estoy seguro de si esa es la palabra adecuada: / Pero gracias por aclarar eso para todos.
Biclops

15

Como han sugerido otros, puede usar CATransaction.
El problema surge porque CALayer tiene una duración de animación implícita predeterminada de 0,25 segundos.

Por lo tanto, una alternativa más fácil (en mi opinión) setDisableActionses usar setAnimationDurationcon un valor de 0.0.

[CATransaction begin];
[CATransaction setAnimationDuration:0.0];
layer.position = CGPointMake(x, y);
[CATransaction commit];

Fácil de recordar, fácil de entender cuando vuelve a leer el código y más fácil de escribir. ¡Gracias!
Mr. T

3

Combinando respuestas anteriores aquí para Swift 4, para hacer claramente explícita la duración de la animación ...

extension CALayer
{
    class func perform(withDuration duration: Double, actions: () -> Void) {
        CATransaction.begin()
        CATransaction.setAnimationDuration(duration)
        actions()
        CATransaction.commit()
    }
}

Uso...

CALayer.perform(withDuration: 0.0) {
            aLayer.frame = aFrame
        }
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.