Why does UIScrollView automatically restore the zoomScale property?

I have an extended UIScrollView, which is taken directly from the Apple sample documentation project "ZoomingPDFViewer"

If you get this project, you will notice that its UIScrollView extension class “PDFScrollView” has a blatant error on startup (on the SIM device and)

If you zoom out far enough, you will eventually hit the zoom limits set by StoryBoard ... but then you can just pinch and go right outside.

I am trying to implement this class in my own project, and this error came with it.

For some reason, after the zoom completes, the zoomScale UIScrollView property is arbitrarily set to 1.0, so you can effectively zoom to infinity ... remember that zoomScale reset does NOT affect the content ... so you can simply zoom in and out until The PDF file in the demo will not be just a pixel on the screen.

I had never seen this before, and before I did a bunch of custom UIScrollViews.

I tried to follow a few steps but nothing works. Does anyone know what could cause UIScrollView to reset it to scale?

I thought it might be because subviews are removed and added during scaling, but I put a dummy view in the scroll view to act as a binding, and that didn't work either.

As I already said. ZoomingPDFViewer is the exact code I work with using iOS 6.0

Any ideas would be appreciated. Code example below

- (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]); } 

This is the end-of-scroll delegate ... both of these logs create a scaling that is exactly what you expect ... so ... any number other than 1.0 if you really zoomed in.

Then layoutSubviews is called ..

 // 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 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]); } 

At this point, zoomScale reports as 1.0 no matter what ... it tracks 0.003 seconds after the End Zoom delegate method reports the correct scale.

+4
source share
2 answers

The problem is that in the Apple code example, they return a view for scaling for - (UIView *)viewForZoomingInScrollView: which is constantly being - (UIView *)viewForZoomingInScrollView: . Ever soon, the return value refers to another object, and UIScrollView interprets this as resetting the zoom scale, which allows you to scroll to infinity.

I don’t know yet how to correctly fix the Apple example code, but the working solution involves binding the UIScrollView to a dummy view that will never reset, and then scale everything else manually.

+2
source

Yes, this happened once around iOS 3. zoomScale always refers to the current state of scrollView, and not to the global dimension. After each increase, you need to recalculate the minimum and maximum zoom scales relative to the current general zoom scale.

This is the code I used in the past. It should give you the gist of the process:

First, take the desired values:

 - (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 ... } 

and then the rest ( self.navigationView is a view of the scroll content):

 - (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 applied a fake scale and translate transform, and // altered the scrollview 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]; } 

Hope this helps.

+4
source

Source: https://habr.com/ru/post/1436843/


All Articles