Getting subViews' frames in Storyboard

断了今生、忘了曾经 提交于 2019-12-18 17:11:30

问题


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:

  • create a new, single view project with "using Storyboard" checked
  • add a single UIView to the default existing 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)
  • option-click the 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 directive
  • control-click-and-drag from the UIView in the Storyboard to ViewController.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.


回答1:


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);
}



回答2:


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:

  1. segue-push does not cause subViews to be laid out at -viewDidLayoutSubviews (they are instead laid out at some other time just before -viewDidAppear).
    Whereas...
  2. 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 subViews 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.

A few notes:

  1. Yes, I am calling [super viewDidLayoutSubviews] at the beginning of -viewDidLayoutSubviews.
  2. The only view that has been laid out at -viewDidLayoutSubviews is self.view (ViewController2's initial view, as connected in Storyboard's connections panel. in my case - self.view is a scrollView).

To resolve:

  1. in ViewController2, I created an outlet self.bottomView for the view that contained self.customButton.
  2. in ViewController2's -viewDidLayoutSubviews, I call [self.bottomView layoutSubviews]
    • This will then cause customButton's frame/bounds to be properly set.
  3. Next, I call [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 subViews of self.view and not to any subViews of those subViews.
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 "subViews of subViews") by the time -viewDidLayoutSubviews is called.



来源:https://stackoverflow.com/questions/13406574/getting-subviews-frames-in-storyboard

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!