2012-08-10 14 views
6

Tengo algunos problemas de rendimiento con algún código que he escrito para cambiar el tamaño de un CALayer usando el tacto. Funciona bien, pero la animación está lejos de ser lo suficientemente ágil y se queda atrás de la ubicación táctil.El tamaño de CALayer es lento

CGPoint startPoint; 
CALayer *select; 

- (CGRect)rectPoint:(CGPoint)p1 toPoint:(CGPoint)p2 { 
    CGFloat x, y, w, h; 
    if (p1.x < p2.x) { 
     x = p1.x; 
     w = p2.x - p1.x; 
    } else { 
     x = p2.x; 
     w = p1.x - p2.x; 
    } 
    if (p1.y < p2.y) { 
     y = p1.y; 
     h = p2.y - p1.y; 
    } else { 
     y = p2.y; 
     h = p1.y - p2.y; 
    } 
    return CGRectMake(x, y, w, h); 
} 

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    UITouch *t1 = [[[event allTouches]allObjects]objectAtIndex:0]; 
    CGPoint loc = [t1 locationInView:self]; 
    startPoint = loc; 
    lastPoint = CGPointMake(loc.x + 5, loc.y + 5); 

    select = [CALayer layer]; 
    select.backgroundColor = [[UIColor blackColor]CGColor]; 
    select.frame = CGRectMake(startPoint.x, startPoint.y, 5, 5); 
    [self.layer addSublayer:select]; 
} 

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 
    UITouch *t1 = [[[event allTouches]allObjects]objectAtIndex:0]; 
    CGPoint loc = [t1 locationInView:self]; 
    select.bounds = [self rectPoint:startPoint toPoint:loc]; 
} 

¿Hay una mejor manera de lograr esto?

Respuesta

24

El retraso se debe a que está cambiando la propiedad bounds de la capa, que es una propiedad animable.

Con CALayers (la CA significa animación central ...) cualquier cambio en una propiedad animable se animará por defecto. Esto se llama animación implícita. La animación predeterminada tarda 0.25 segundos, por lo que si la actualiza con frecuencia, por ejemplo, durante el procesamiento de toques, esto se sumará y causará un retraso visible.

Para evitar esto, se debe declarar una transacción de animación, desactivar las animaciones implícitas, a continuación, cambiar las propiedades:

[CATransaction begin]; 
[CATransaction setDisableActions:YES]; 
layer.bounds = whatever; 
[CATransaction commit]; 
+2

me hubiera llevado al menos un día resolver eso de forma independiente, gracias stack + jrturton. –

1

respuesta aceptada en Swift 3/4:

CATransaction.begin() 
CATransaction.setDisableActions(true) 
layer.bounds = whatever 
CATransaction.commit() 

Vale la pena mencionar que esto también se aplica a las propiedades .frame, por ejemplo, al cambiar el tamaño de una AVPlayerLayer:

override func layoutSubviews() { 
    CATransaction.begin() 
    CATransaction.setDisableActions(true) 
    playerLayer.frame = self.bounds 
    CATransaction.commit() 
}