views:

561

answers:

2

I have a very simple UIScrollView example that simply doesn't do what it's suposed to. Not sure if it's a bug with the API or a bug in my code.

Basically, I've got a UIViewController with a UIScrollView as it's view. When I add it to the UIWindow and change the orientation of the iPad I log out the UIScrollViews size, which is incorrectly(?) reported.

Here's my UIViewController implementation:

@implementation CustomViewController
- (void)loadView {
  scrollView = [[[UIScrollView alloc] init] autorelease];
  scrollView.delegate = self;
  scrollView.backgroundColor = [UIColor redColor];
  self.view = scrollView;
}

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
  CGSize rect = scrollView.frame.size;
  NSLog(@"will rotate w%f h%f", rect.width, rect.height);
}

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
  CGSize rect = scrollView.frame.size;
  NSLog(@"will animate rotation w%f h%f", rect.width, rect.height);
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
  CGSize rect = scrollView.frame.size;
  NSLog(@"did rotate w%f h%f", rect.width, rect.height);
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
  return YES;
}

@end

When I run the above code I see the following entries in my console:

2010-07-11 11:03:05.214 Untitled2[6682:207] will rotate w768.000000 h1004.000000
2010-07-11 11:03:05.214 Untitled2[6682:207] will animate rotation w748.000000 h1024.000000
2010-07-11 11:03:05.619 Untitled2[6682:207] did rotate w748.000000 h1024.000000
2010-07-11 11:03:07.951 Untitled2[6682:207] will rotate w748.000000 h1024.000000
2010-07-11 11:03:07.958 Untitled2[6682:207] will animate rotation w768.000000 h1004.000000
2010-07-11 11:03:08.367 Untitled2[6682:207] did rotate w768.000000 h1004.000000

As you can see, the orientation changes does resize the UIScrollView, but only to allow the new statusbar. I would expect that the width and height drastically change, as the UIScrollView is how wider than it is high and vice versa.

Is there a way to get the UIScrollView to report it's real size?

A: 

Views will not automatically resize themselves when their superviews resize unless you specifically set them to be. For that scroll view you would need to tell it to resize its width and height when its superview does.

scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
rickharrison
Unfortunately after adding a resizing mask I still get the invalid dimensions coming back.Visually everything is fine, but I'm not able to rely on the frame dimensions.I've hacked around it by detecting the devices orientation and flipping the width and height when landscape - it's not ideal, but it works.
d2kagw
A: 

I have noticed that determining the new contentSize in didRotateFromInterfaceOrientation is also impossible if you start out with an iPhone NIB file instead of a dedicated iPad NIB file: the frames in the iPhone NIB file are much smaller and hence the calculated height of the content becomes much greater than it should be when you're actually on an iPad. Apple DID say that I MUST create a separate iPad NIB file...

So, I do also get the old dimensions in didRotateFromInterfaceOrientation, but for me it is now less of a problem, since iOS does handle everything OK once I start out with the right NIB file. Still, it seems less intuitive to me that in the didRotateFromInterfaceOrientation method the frame dimensions are incorrect for the current view.

PS. I did find a solution in the end, just use the notifications instead of didRotateFromInterfaceOrientation.

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(orientationChanged:)
                                                 name:UIDeviceOrientationDidChangeNotification
                                               object:nil];

Then in the orientationChanged method, adjust the views to the new frames. I had one final problem: if the initial orientation was different from the orientation in the nib the view would still be wrong, I solved that by creating a new NIB file especially for the landscape view. In the init method the viewcontroller chooses which NIB it loads based on the current orientation.

Huib Verweij