En iOS 4.0, ¿por qué UIScrollView zoomToRect: animated: no activa los delegados scrollViewDidScroll o scrollViewDidZoom mientras anima?
ios4 uiscrollviewdelegate (4)
Necesito monitorear de cerca la escala de la vista de desplazamiento para poder actualizar los elementos de la vista de contenido (una subvista que administra varios CALayers ) de acuerdo con el zoom animado de la vista de desplazamiento.
En iOS 3.1, todo funciona como se espera, uso zoomToRect: animated: y el mensaje scrollViewDidScroll: de UIScrollViewDelegate se llama repetidamente mientras se lleva a cabo la animación , lo que me permite actualizar los elementos de la subvista según el zoom real.
El mismo código en iOS 4.0 no presenta el mismo comportamiento. Cuando llamo a zoomToRect: animated:, los delegados ( scrollViewDidScroll: y scrollViewDidZoom ) solo reciben llamadas una vez , lo que hace que mis subelementos queden desincronizados hasta que finalice la animación. De hecho, los subelementos saltan inmediatamente y luego quedan atrapados por la animación de zoom hasta que todo está en el lugar correcto. Es como si la animación no estuviera recogiendo las modificaciones en las subvistas CALayers .
He intentado animar manualmente con bloques de animación, pero la situación es la misma, no hay llamadas de devolución de llamada progresivas. También he probado KVO, pero no me queda claro cómo utilizar una animación administrada por UIScrollView.
¿Existe alguna solución alternativa para iOS 4 que me permita aumentar el valor de escala a mis subvistas cuando la escala UIScrollView está animada?
¿Es viable actualizar todas las subvistas dentro de un bloque de animación (o comenzar / commitAnimation)? Algo como:
[self zoomToRect:zoomRect animated:YES];
[UIView animateWithDuration:1.0
animations:^ {
// change your subviews
}
];
Brutal pero funciona.
Definir algunas propiedades:
@property (nonatomic, strong) UIView *zoomedView;
@property (nonatomic, strong) CADisplayLink *displayLink;
@property (nonatomic) CGFloat currentScale;
Informe a UIScrollView
qué UIView
se UIView
:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.zoomedView;
}
Regístrese para un CADisplayLink
ticks. También ejecuta Core Animation, por lo que se eliminará en los mismos intervalos:
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkTick)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
Verifique la presentationLayer
de zoomedViewLayer para los valores actuales.
- (void)displayLinkTick
{
CALayer *zoomedLayer = self.zoomedView.layer.presentationLayer;
CGFloat scale = zoomedLayer.transform.m11;
if (scale != self.currentScale) {
self.currentScale = scale; // update property
// the scale has changed!
}
}
En IOS 4.0, el sistema operativo realiza las animaciones; supongo que para aprovechar al máximo la aceleración de hardware basada en GPU. Como una desventaja de eso, se vuelve más difícil animar un valor que se deriva de otro valor (animado). Como en su caso, las posiciones de las subvistas que dependen del nivel de zoom de UIScrollView. Para que esto suceda, debe configurar la animación de las subvistas para que vaya en paralelo con la animación del zoom. Intenta algo como:
[UIView animateWithDuration:0.5 delay:0
options:UIViewAnimationOptionLayoutSubviews
animations:^{
theScrollView.zoomScale = zoomScale;
// layout the subviews here
} completion:^(BOOL finished) {}];
Esto debería establecer las propiedades de marco de las subvistas desde el mismo contexto de animación, y por lo tanto, deberían estar animadas juntas por el sistema operativo.
Vea también las respuestas a esta pregunta: Cómo hacer que UIScrollView envíe mensajes scrollViewDidScroll durante las animaciones
Regístrese para KVO de la propiedad zoomScale
de UIScrollView
después de llamar a zoomToRect:animated:
[scrollView addObserver:self
forKeyPath:@"zoomScale"
options:(NSKeyValueObservingOptionNew |
NSKeyValueObservingOptionOld)
context:NULL];
Luego, implementa este método:
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ([keyPath isEqual:@"zoomScale"]) {
// use the new zoomScale value stored
// in the NSKeyValueChangeNewKey change
// dictionary key to resize your subviews
}
// be sure to call the super implementation
// if the superclass implements it
[super observeValueForKeyPath:keyPath
ofObject:object
change:change
context:context];
}
Echa un vistazo a la documentation KVO.