为什么UIScrollView会自动重置其zoomScale属性?

时间:2012-09-28 15:16:09

标签: iphone objective-c ios uiscrollview uikit

我有一个扩展的UIScrollView,直接取自Apple文档示例项目“ZoomingPDFViewer”

如果你得到这个项目,你会注意到它的UIScrollView扩展类“PDFScrollView”在你运行时有一个明显的错误(在sim和设备上)

如果捏缩放的距离足够远,你最终会达到StoryBoard设置的缩放比例限制......但是,你可以重新捏合并超越限制。

我一直在尝试在我自己的项目中实现这个类,并且这个bug随之而来。

由于某些原因,在缩放结束后,UIScrollView的zoomScale属性被任意设置回1.0,因此您可以有效地将缩放设置为无限...请记住,重置的zoomScale不会影响内容。 ..所以你可以继续缩小,直到演示中的PDF只是屏幕上的一个像素。

我之前从未见过这个,之前我已经完成了大量的自定义UIScrollViews。

我已经尝试了几个步骤来解决它,但似乎没有任何工作。有谁知道什么会导致UIScrollView以这种方式重置其zoomScale?

我认为可能是因为子视图在缩放期间被删除并添加,但我在滚动视图中放置了一个虚拟视图作为锚点,但这也不起作用。

就像我说的那样..使用iOS 6.0,ZoomingPDFViewer是我正在使用的确切代码

任何想法都将不胜感激。下面的示例代码

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

}

这是结束滚动委托...这两个日志都会产生一个与你期望的一样的zoomScale ......所以......除了1.0以外的任何数字,假设你实际放大了。

然后调用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]);
}

此时,无论如何,zoomScale都会报告为1.0 ...在最终缩放委托方法报告适当的缩放比例后,此跟踪0.003秒。

2 个答案:

答案 0 :(得分:4)

是的,这发生在iOS 3的某个时间。zoomScale总是相对到scrollView的当前状态,而不是全局测量。每次缩放后,您需要重新计算相对于当前整体缩放比例的最小和最大缩放比例。

这是我过去使用的一些代码。它应该给你这个过程的要点:

早期,抓住您需要的值:

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

然后其余的(self.navigationView是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
//   altered 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];
}

希望这有帮助。

答案 1 :(得分:2)

这里的问题是,在Apple的示例代码中,他们返回的视图将被缩放为- (UIView *)viewForZoomingInScrollView:,并且不断被重新实例化。很快,返回值就是另一个对象,UIScrollView将其解释为缩放比例的重置,从而允许您滚动到无限远。

我还不知道如何正确修复Apple的示例代码,但是一个有效的解决方案是将UIScrollView固定到一个永远不会被重置的虚拟视图,然后手动扩展其他所有代码。