UIScrollView在iOS 8和iOS 7上的frame大小不同。

7
我实现了一个视图控制器,简单地显示一张图片,并允许用户通过捏合手势进行缩放/平移。它在iOS 7上运行良好,但是在iOS 8上,滚动视图的框架大小不同,结果是当在iOS 8上运行时,iPhone上的图像被缩放得太远,iPad上的图像被缩放得太小。这是因为滚动视图帧的宽度为600pt,即在故事板中的尺寸(使用大小类的通用故事板)。但我有自动布局约束,应该确保滚动视图伸展以填充可用空间 - 在iPad上应该为768pt。这在iOS 7上是这样的,但在iOS 8上却不是。
设置如下:在界面构建器中,我有一个包含UIView的UIViewController,其包含具有自动布局约束的UIScrollView,如右侧、左侧、底部和顶部空间给父视图。然后在viewDidLoad中:
    UIImage *image = [UIImage imageNamed:@"image"];
    self.imageView = [[UIImageView alloc] initWithImage:image];
    self.imageView.contentMode = UIViewContentModeScaleAspectFit;
    self.imageView.frame = CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height);

    [self.scrollView addSubview:self.imageView];
    self.scrollView.contentSize = image.size;

    #warning Bug here - scroll view frame is 600pt on iOS 8 - should be 768 for iPad
    NSLog(@"scroll view frame wid: %f", self.scrollView.frame.size.width);

我发现如果我把同样的NSLog放在viewDidAppear中,frame的宽度就是正确的768pt。我试着把这段代码移到viewWillAppear而不是viewDidLoad,但结果相同 - 在viewWillAppear中它仍然是600。因此,滚动视图正确地拉伸以填充显示屏,但直到它出现在屏幕上之后才这样做。我需要在图像出现在屏幕上之前获得正确的框架大小,以便我可以计算正确的最小和最大缩放值。
我该怎么做才能修复它并确保它适用于iOS 7和8?

当您说“600pt,在故事板中的大小”时,您是指常量大小约束还是临时的“占位符”内在大小值? - Ian MacDonald
@IanMacDonald 当使用通用的Storyboard时,场景的默认大小为600。由于滚动视图通过自动布局来拉伸填充宽度/高度,因此其默认大小也为600,但它应该拉伸以填满整个视图的大小。 - Jordan H
是的,我知道默认大小为600。我想知道你的滚动视图是否在我提到的这两个字段中报告了它的600,还是只在计算的框架字段中。滚动视图是否有一个没有拉伸的父视图? - Ian MacDonald
@IanMacDonald 不,父视图(UIView)会拉伸以填满显示区域,而 UIScrollView 始终保持 600x600。除了四个方向到父视图的约束外,没有其他约束,并且内在内容大小是系统定义的默认值。 - Jordan H
实际上,我错了。UIScrollView 在出现后会拉伸以填充显示屏,但在 viewDidLoad 中它仍然是 600x600。将更新问题。 - Jordan H
2个回答

22

我已经解决了这个问题。由于某种原因,在iOS 8上,viewDidLoad处于生命周期的太早阶段,无法获取滚动视图调整后的框架,但在iOS 7上却可以正常工作。viewWillAppear也太早了,viewWillLayoutSubviews也一样。

为了解决这个问题,我只需将需要使用滚动视图框架大小的代码移至viewDidLayoutSubviews中,最终可以正确获得它出现时的大小。


3
如果您想避免任何视觉抖动,您可以在 viewDidLayoutSubviews 中设置您的滚动视图隐藏直到您调整它的框架。 - Ian MacDonald
非常感谢。我刚刚花了几个小时试图找出为什么滚动视图中的第一张图片大小与其余图片不同(因为它们在稍后的时间点被调整大小)。 - Hobsie

1
我也曾经遇到类似的问题。我通过在代码中程序性地更改滚动视图内的 contentView 的宽度来解决它。在 ViewDidLoad 中,我调用了这个方法。
func setupWidthOfContentView(){

    let screen = UIScreen.mainScreen().bounds
//        println("Width: \(screen.size.width) Height: \(screen.size.height)")

    var constW = NSLayoutConstraint(item: vwContentView, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: screen.size.width)
    vwContentView.addConstraint(constW)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接