I’ve got a UIViewController with an iPad xib in portrait orientation. When my iPad is in landscape orientation and I put that view controller into my UISplitViewController’s detail pane, it gets automatically resized to fit which is great.
However, when I’m configuring my views in -viewDidLoad, the final size of the views is not yet in landscape orientation/size.
The -didRotateFromInterfaceOrientation: method and the other methods associated with it do not get called when the UIViewController is loaded already in landscape, so when and where am I able to properly set the contentSize of the scroll view and it’s contents?
I only want my scroll view to scroll vertically, so I want to make sure that my contentView inside the scrollView is re-fit to the width of the view controller in whatever orientation it is in.
No matter what .frame or .bounds I check, whether it’s on my view, my scroll view, or even the detail view controller of my SplitViewController show me what my ACTUAL size is. When in landscape using a UISplitViewController, the left hand side is 320px wide which means the right hand side shouldn’t be more than 704px wide, but whenever I check the frames and the bounds of my view and my scrollview, they report as 768px wide which is not correct.
My scrollview is CLEARLY only 704px wide because I can see the scroll indicators correctly.
What am I missing?
Here is my code in -viewDidLoad…
CGSize textSize = [self.purchase.textDescription sizeWithFont:self.labelTextDescription.font constrainedToSize:allowedSize lineBreakMode:UILineBreakModeWordWrap];
CGRect textFrame = self.labelTextDescription.frame;
textFrame.size.height = textSize.height;
self.labelTextDescription.frame = textFrame;
CGRect contentFrame = self.contentView.frame;
contentFrame.size.height += textSize.height;
if (contentFrame.size.width > self.scrollView.frame.size.width) {
contentFrame.size.width = self.scrollView.frame.size.width;
}
self.contentView.frame = contentFrame;
[self.scrollView addSubview:self.contentView];
self.scrollView.contentSize = self.contentView.frame.size;
The proper time to lay out your views and set your scroll view’s
contentSizeis during the layout phase of the run loop. During this phase, UIKit sends thelayoutSubviewsmessage to any view that has been marked as needing layout and is in a window. A view is automatically marked as needing layout when various things happen, including when it is first added to a window hierarchy, when it is given a new subview, and when its size changes. You can also manually mark a view as needing layout by sending it thesetNeedsLayoutmessage.By the time a view receives the
layoutSubviewsmessage, UIKit has already sentlayoutSubviewsto any of the view’s ancestors (its superview and up) that needed it, and it has already had its frame adjusted based on its autoresizing mask or autolayout constraints, and its own subviews’ frames have already been adjusted based on their autoresizing masks or autolayout constraints.If
self.viewis already a custom subclass ofUIView, the best approach is simply to overridelayoutSubviewsin that class. Put your layout code there, and set the scroll view’scontentSizethere.If you’re not using a custom subclass, and you don’t want to create one, then you can do the layout in your view controller’s
viewWillLayoutSubviewsorviewDidLayoutSubviewsmethod, if you’re deployment target is iOS 5.0 or later. You can probably guess when these messages are sent. 🙂During autorotation, all of these messages (
layoutSubviews,viewWillLayoutSubviews, andviewDidLayoutSubviews) are sent inside the autorotation’s animation block, so if you do your layout in one of these methods, you also get the benefit that the changes to your layout will be animated during the autorotation animation.