I just want (for now) to get the dimensions of a subview on the view controller's instantiation.
[This is a reduction to as simple a case I can find of a previous question. I am trying to figure out why subViews of scenes in Storyboards are not behaving the way I expect, which is to say: like XIBs do - I just want to get dimensions of my subviews before anything is actually drawn to the screen]
To condense the problem down to a new, clean project, I do this:
MainStoryboard_iPad.storyboard
(and change its background to green to make it more easily seen - beyond shrinking the dimensions some, this is the only change I make from the default UIView I drag onto the scene)ViewController.h
file in the navigator to bring it up in its own frame underneath the Storyboard frame and insert a pair of braces underneath the @interface
directiveViewController.h
and tell it to name the outlet firstViewFirstSubView
So we now have for ViewController.h
:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
{
IBOutlet UIView *firstViewFirstSubView;
}
@end
Then, I add this method to the ViewController.m:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(@"View Controller will appear. firstViewFirstSubView: %@ ", firstViewFirstSubView);
NSLog(@"subView's dimmensions: %f by %f at %f, %f", firstViewFirstSubView.frame.size.width,
firstViewFirstSubView.frame.size.height,
firstViewFirstSubView.frame.origin.x,
firstViewFirstSubView.frame.origin.y);
}
At this point, I expect to be able to get the dimensions of the UIView subview. I get all 0s, though:
2012-11-15 15:21:00.743 StoryboardViewBounds[11132:c07] View Controller will appear. firstViewFirstSubView: <UIView: 0x9379730; frame = (0 0; 0 0); autoresize = TM+BM; layer = <CALayer: 0x9378e40>>
2012-11-15 15:21:00.744 StoryboardViewBounds[11132:c07] subView's dimmensions: 0.000000 by 0.000000 at 0.000000, 0.000000
What am I doing wrong? It seems like this should be very straightforward, so I think I must be missing something simple, whether throwing the right switch in the Storyboard editor or implementing a method that Storyboard needs.
Those dimensions are calculated and set when the call to layoutSubviews
is made, which occurs after viewWillAppear
. After layoutSubviews
is called on the UIVIew you can get the dimensions.
Look at implementing this method in your view controller: viewDidLayoutSubviews
. At this point you should be able to get dimensions of your subviews. Note that this call is available starting in iOS 5.0 but since you reference storyboards I assume you are working at or above that anyway.
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
NSLog(@"View Controller did layout subviews. firstViewFirstSubView: %@ ", firstViewFirstSubView);
NSLog(@"subView's dimmensions: %f by %f at %f, %f", firstViewFirstSubView.frame.size.width,
firstViewFirstSubView.frame.size.height,
firstViewFirstSubView.frame.origin.x,
firstViewFirstSubView.frame.origin.y);
}
There is a Related issue that I am compelled to address, which hopefully will save someone else a day of debugging:
I am finding out that in Storyboard:
segue-push
does not cause subView
s to be laid out at -viewDidLayoutSubviews
(they are instead laid out at some other time just before -viewDidAppear
).segue-modal
and [navController.storyboard presentViewController:]
does cause subViews
to be laid out at -viewDidLayoutSubviews
. The solution is to put [self.mySubView layoutSubviews]
within the viewController
's -viewDidLayoutSubviews
method in order to manually load the subView
s within mySubView
.
My case was that I had a custom gradient button that was not properly initializing it's visual appearance.
The button was contained within a scrollView
that contained a CustomView
which contained the custom gradient button.
So, basically... a button within a view within a scrollView
.
The app starts out with a UINavigationController
having some other ViewController1
loaded.ViewController1
contains a button which, when pressed, launches a storyboard segue-push
to ViewController2
.
(this was arranged in storyboard by control-dragging from the button in ViewController1
to ViewController2
).
ViewController2
contains the scrollview
/customView
/customButton
.
In ViewController2
's -viewDidLayoutSubviews
, I initialize the customButton
which is a custom Gradient Button having it's own .h/.m files.GradientButton.m
has an initLayers
method which configures it graphically and requires the bounds
/frame
property of the button to be initialized.
However...
in ViewController2
's -viewDidLayoutSubviews
, self.customButton
had a frame of 0,0,0,0.
[super viewDidLayoutSubviews]
at the beginning of -viewDidLayoutSubviews
. -viewDidLayoutSubviews
is self.view
(ViewController2
's initial view, as connected in Storyboard's connections panel. in my case - self.view
is a scrollView
).ViewController2
, I created an outlet self.bottomView
for the view that contained self.customButton
. ViewController2
's -viewDidLayoutSubviews
, I call [self.bottomView layoutSubviews]
customButton
's frame/bounds to be properly set. [self.customButton initLayers]
which now properly initializes my custom gradient button. A few notes about ViewController2
's -viewDidLayoutSubviews:
calling [self.view layoutSubviews]
causes bottomView
's frame to be initialized, but NOT customButton
's frame.
In terms of a view hierarchy, -layoutSubviews
applies only to the subView
s of self.view
and not to any subView
s of those subView
s.
This only appears to be the case with storyboard segue-push
.
The storyboard segue-modal
and the programmatic [navController presentViewController]
both seem to correctly initialize all levels of the view hierarchy (all "subView
s of subView
s") by the time -viewDidLayoutSubviews
is called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With