【问题标题】:Why is UIScrollView is resetting its zoomScale property automatically?为什么 UIScrollView 会自动重置其 zoomScale 属性?
【发布时间】:2012-09-20 12:02:45
【问题描述】:

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

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

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

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

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

我以前从未见过这种情况,而且我之前做过大量的自定义 UIScrollViews。

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

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

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

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

- (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...这会在 End Zoom 委托方法报告正确的缩放比例后 0.003 秒跟踪。

【问题讨论】:

    标签: iphone objective-c ios uiscrollview uikit


    【解决方案1】:

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

    我(尚)不知道如何正确修复 Apple 的示例代码,但可行的解决方案是将 UIScrollView 固定到一个永远不会重置的虚拟视图,然后手动缩放其他所有内容。

    【讨论】:

      【解决方案2】:

      是的,这发生在 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];
      }
      

      希望这会有所帮助。

      【讨论】:

      • 还有更多内容,因为如果我只是创建一个空项目,在滚动视图中放置一个通用视图,并设置缩放范围,它就可以正常工作。是不是仅仅通过实现 scrollViewDidEndZooming: 整个事情就崩溃了?
      • 顺便说一句,您是否正在实施viewForZoomingInScrollView:? scrollView 需要知道您正在操作哪个视图来判断结束比例值是什么。
      • 不知道。我刚刚使用上面的代码自己创建了一个项目。我将一个大图像放在一个小的 scrollView 中,它会像我期望的那样缩放、滚动等。一定有其他事情发生。
      猜你喜欢
      • 1970-01-01
      • 2012-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-10
      • 2012-04-01
      • 2011-05-03
      • 1970-01-01
      相关资源
      最近更新 更多