¿Por qué UIScrollView está restableciendo automáticamente su propiedad zoomScale?

Tengo un UIScrollView extendido que se toma directamente del proyecto de ejemplo de documentation de Apple "ZoomPDFViewer"

Si obtienes este proyecto, notarás que es la class de extensión UIScrollView "PDFScrollView" tiene un error deslumbrante cuando la ejecutas (en el dispositivo sim AND)

Si pellizcas el zoom lo suficiente, eventualmente alcanzarás los límites de la escala del zoom establecidos por el StoryBoard … pero luego, puedes volver a pellizcar y pasar justo por encima de los límites.

He estado intentando implementar esta class en mi propio proyecto, y este error ha llegado.

Por alguna razón, una vez que el zoom finaliza, la propiedad zoomScale del UIScrollView se vuelve a establecer arbitrariamente en 1.0, por lo que puede pellizcar de manera efectiva el zoom hasta el infinito … tenga en count que el zoomScale que se restablece NO afecta el contenido … solo puede seguir haciendo zoom hasta que el PDF en la demostración sea solo un píxel en la pantalla.

Nunca antes había visto esto y he hecho toneladas de UIScrollViews personalizadas anteriormente.

He intentado algunos pasos para resolverlo, pero nada parece funcionar. ¿Alguien sabe qué haría que un UIScrollView restablezca su zoomScale de esa manera?

Pensé que podría ser porque las subvistas se eliminan y se agregan durante los zoom, pero puse una vista ficticia en la vista de desplazamiento para que actúe como un ancla, y tampoco funcionó.

Como dije … ZoomingPDFViewer es el código exacto con el que estoy trabajando, usando iOS 6.0

Cualquier idea sería apreciada. Código de ejemplo a continuación

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale { NSLog(@"Ending Zoom %0.2f %0.2f", [self zoomScale], scale); // Set the new scale factor for the TiledPDFView. _PDFScale *= scale; // Calculate the new frame for the new TiledPDFView. CGRect pageRect = CGPDFPageGetBoxRect(_PDFPage, kCGPDFMediaBox); pageRect.size = CGSizeMake(pageRect.size.width*_PDFScale, pageRect.size.height*_PDFScale); // Create a new TiledPDFView based on new frame and scaling. TiledPDFView *tiledPDFView = [[TiledPDFView alloc] initWithFrame:pageRect scale:_PDFScale]; [tiledPDFView setPage:_PDFPage]; // Add the new TiledPDFView to the PDFScrollView. [self addSubview:tiledPDFView]; self.tiledPDFView = tiledPDFView; NSLog(@"End of end zoom %0.2f", [self zoomScale]); } 

Este es el delegado de desplazamiento final … ambos de estos loggings producen una escala de zoom que es exactamente lo que cabría esperar … así que … cualquier número que no sea 1.0, suponiendo que haya hecho un zoom.

Luego se llama a layoutSubviews ..

 // Use layoutSubviews to center the PDF page in the view. - (void)layoutSubviews { [super layoutSubviews]; // Center the image as it becomes smaller than the size of the screen. CGSize boundsSize = self.bounds.size; CGRect frameToCenter = self.tiledPDFView.frame; // a bunch of code that sets frameToCenter self.tiledPDFView.frame = frameToCenter; self.backgroundImageView.frame = frameToCenter; /* To handle the interaction between CATiledLayer and high resolution screens, set the tiling view's contentScaleFactor to 1.0. If this step were omitted, the content scale factor would be 2.0 on high resolution screens, which would cause the CATiledLayer to ask for tiles of the wrong scale. */ self.tiledPDFView.contentScaleFactor = 1.0; NSLog(@"Subviews Layed Out %0.2f", [self zoomScale]); } 

En este punto, zoomScale reporta como 1.0 sin importar qué … esto rastrea 0.003 segundos después de que el método de Delegación de Zoom de Fin informe una escala de zoom apropiada.

Sí, esto sucedió en algún momento alnetworkingedor de iOS 3. zoomScale siempre está relacionado con el estado actual de scrollView, no con una medición global. Después de cada zoom, debe recalcular las escalas de zoom mínimas y máximas en relación con la escala de zoom general actual.

Este es un código que he usado en el pasado. Debería darle la esencia del process:

Al principio, toma los valores que necesitas:

 - (void) viewDidLoad { [super viewDidLoad]; ... // Squirrel away min and max zoom values from nib sMinZoomScale = self.scrollView.minimumZoomScale; // the very minimum sMaxZoomScale = self.scrollView.maximumZoomScale; // the very maximum sGlobalZoomScale = 1.0f; // we're currently at 100% size ... } 

y luego el rest ( self.navigationView es la vista de contenido de scrollView):

 - (void) scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale { // after a zoom, change the resolution of our map sGlobalZoomScale *= scale; // Peg the scale to minZoom and maxZoom, in case of rounding errors sGlobalZoomScale = MIN(MAX(sMinZoomScale, sGlobalZoomScale), sMaxZoomScale); self.navigationView.globalZoomScale = sGlobalZoomScale; self.navigationView.globalScaleTransform = self.globalScaleTransform; [self updateResolution]; // throw out all tiles so they'll reload at the new resolution [self.navigationView setNeedsDisplay]; } // By the time we get here, the scrollview's applied a fake scale and translate transform, and // altenetworking the scrollview's zoom scale. BUT, the navigationview is as it ever was. - (void) updateResolution { CGFloat zoomScale = [self.scrollView zoomScale]; CGSize oldContentViewSize = self.navigationView.frame.size; // zooming properly resets contentsize as it happens. CGSize newContentSize = self.scrollView.contentSize; CGPoint newContentOffset = self.scrollView.contentOffset; CGFloat xMult = newContentSize.width / oldContentViewSize.width; CGFloat yMult = newContentSize.height / oldContentViewSize.height; newContentOffset.x *= xMult; newContentOffset.y *= yMult; CGFloat currentMinZoom = self.scrollView.minimumZoomScale; CGFloat currentMaxZoom = self.scrollView.maximumZoomScale; CGFloat newMinZoom = currentMinZoom / zoomScale; CGFloat newMaxZoom = currentMaxZoom / zoomScale; // Reset zoom scales temporarily so we can patch up the revised content view // don't call our own set..zoomScale, 'cause they eventually call this method. Infinite recursion is uncool. [self.scrollView setMinimumZoomScale:1.0f]; [self.scrollView setMaximumZoomScale:1.0f]; [self.scrollView setZoomScale:1.0f animated:NO]; [self.navigationView setFrame:CGRectMake(0.0f, 0.0f, newContentSize.width, newContentSize.height)]; [self.scrollView setContentSize:newContentSize]; [self.scrollView setContentOffset:newContentOffset animated:NO]; [self.scrollView setMinimumZoomScale:newMinZoom]; [self.scrollView setMaximumZoomScale:newMaxZoom]; } 

Espero que esto ayude.

El problema aquí es que en el código de ejemplo de Apple, están devolviendo una vista para escalar - (UIView *)viewForZoomingInScrollView: que constantemente se vuelve a instancia. Después de siempre, el valor de retorno es a un object diferente, y UIScrollView lo interpreta como un restablecimiento de la escala del zoom, lo que le permite desplazarse hasta el infinito.

No sé (aún) cómo corregir correctamente el código de ejemplo de Apple, pero una solución de trabajo implicaría poner el UIScrollView en una vista ficticia que nunca se reiniciaría, y luego escalar todo lo demás manualmente.