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

Mel
fuente
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];
Ben Gottlieb
fuente
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
}
LlorandoHipopótamo
fuente
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.

Biclops
fuente
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];
Así que sobre eso
fuente
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
        }
Giles
fuente