7

I implemented a view controller that simply displays a single image and allows the user to pinch to zoom in/pan around the image. It works great on iOS 7, but on iOS 8 the scroll view's frame is a different size, and the end result is the image is zoomed in too far on iPhone and zoomed out too far on iPad when running on iOS 8. This is because the scroll view frame's width is 600pt, which is its size in the storyboard (Universal Storyboard using size classes). But I have autolayout constraints that are supposed to ensure the scroll view stretches to fill the available space - it should be 768pt on iPad. That is the case on iOS 7 but not iOS 8.

This is the setup: In Interface Builder, I have a UIViewController that contains a UIView which contains a UIScrollView with autolayout contraints trailing, leading, bottom, and top space to the superview. Then in 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);

I discovered if I put that same NSLog in viewDidAppear the frame's width is correctly 768pt. I tried moving that code into viewWillAppear instead of viewDidLoad, but I get the same outcome - it's 600 in viewWillAppear as well. So the scroll view is properly stretching to fill the display but not until after it appears on screen. I need the correct frame size before the image appears on screen so that I may calculate the proper min and max zoom values.

What can I do to fix that and ensure it works for iOS 7 and 8?

Jordan H
  • 52,571
  • 37
  • 201
  • 351
  • When you say "600pt, which is its size in the storyboard", are you referring to a constant size constraint, or a temporary "Placeholder" intrinsic size value? – Ian MacDonald Oct 23 '14 at 17:01
  • @IanMacDonald When using a Universal storyboard the default size of the scene is 600. Since the scroll view stretches to fill the width/height via autolayout, its also 600 by default but it's supposed to stretch to fill the entire view's size. – Jordan H Oct 23 '14 at 17:06
  • Yes, I understand the default size is 600. I was curious if your scroll view is reporting its 600 in either of those two fields I mention, or if it was just in the calculated frame field. Does the scroll view have a superview that isn't stretching? – Ian MacDonald Oct 23 '14 at 17:08
  • @IanMacDonald Nope the superview (`UIView`) stretches to fill the display while the `UIScrollView` always remains 600x600. There is no other constraints besides leading/trailing/top/bottom to superview, and intrinsic content size is the system defined default. – Jordan H Oct 23 '14 at 17:11
  • Actually, no, I'm wrong. The `UIScrollView` is stretching to fill the display after it appears, but in `viewDidLoad` it's still 600x600. Will update question. – Jordan H Oct 23 '14 at 17:13

2 Answers2

22

I've solved it. For some reason, viewDidLoad is too early in the life cycle to obtain the scroll view's adjusted frame on iOS 8, but again it works on iOS 7. viewWillAppear is also too early, as well as viewWillLayoutSubviews.

To solve the problem, I just moved the code where I need to use the scroll view's frame size to viewDidLayoutSubviews which does finally obtain the correct size it will be when it appears.

Jordan H
  • 52,571
  • 37
  • 201
  • 351
  • 3
    If you want to avoid any visual jitter, you could always set your scrollview to hidden until you frame it in `viewDidLayoutSubviews`. – Ian MacDonald Oct 23 '14 at 17:32
  • Massive thanks. I just spent a few hours trying to find out why the first image in a Scroll view was being sized differently than the rest (since they get sized at a later point in time). – Hobsie Apr 08 '15 at 15:20
1

I was also struggling a lot with a similar problem. I solved it by changing the width of the contentView inside the scrollview programatically. In ViewDidLoad i call this method

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)
}
Ibrahim Yildirim
  • 2,731
  • 2
  • 19
  • 31