Using LayoutSubviews

I’m tweaking some of the views in my app that don’t look quite right when rotated from portrait (where everything looks great) to landscape (where there are a few issues). For most of the views I was able to simply use AutoresizingMask and everything looks great in landscape. There are, however, a few views where this isn’t the case and things aren’t aligned quite right in landscape.

It’s been suggested to me a couple times that I should put some or all of my view creation code into a LayoutSubviews method. Only one of the MonoTouch books I have (and I think I have all of them to date) even mentions this method, and it doesn’t go into much depth in explaining it. I’ve looked at a bunch of examples online and in the Xamarin gallery projects, but there’s a lot of variation (and no explanation) and I don’t quite grok the how and why of it. As mentioned up top, a detailed “For Knuckleheads” type of tutorial explaining the ins and outs of using LayoutSubviews in a moderately complex example would be dynamite. Does anyone know of such a tutorial on the web somewhere?

At present I have several views (all hand coded, no use of Interface Builder) where the elements that appear on screen depend on which record (from a database) the user is viewing. In these view controller classes I have some class variables for the subviews (X, Y, width, and height) that always appear for every record. Then for the other conditional elements, I have variables that are calculated based on which elements are going to appear in this particular view instance together (if you follow me).

The variables are assigned values in ViewDidLoad (which I guess I should move to ViewDidAppear now?), and then the actual subviews are all built, and at the end of the ViewDidLoad method they’re all added to the view via AddSubview.

So from what I’ve mostly seen in the examples I’ve examined, is that people just create the Frames for their subviews in LayoutSubviews. LayoutSubviews is a method in some kind of view object class, outside of the method where the view object is implemented, and LayoutSubviews is not called anywhere (that seems strange to me, but I think LayoutSubviews is called automatically?). It’s a little weird to me to have parts of these subviews created in one method and then parts of them in this LayoutSubviews, but I guess that’s how it’s supposed to work?

What I think I need to do, then, is have LayoutSubvies as a method in my ViewController class (outside of ViewDidLoad or ViewDidAppear) and put the Frame creation code in there and leave the rest of it in ViewDidLoad where it is now. I’m a little bit worried about making this work since some of the variables for X, Y, and subview height and subview width that I would want to use in LayoutSubview are dependent on the values of variables that will still be in ViewDidLoad (and I get tripped up by variable scope all the time).

But am I on the right track with that, or am I still completely not getting it?

Also, does LayoutSubviews help at all with making your app universal, or is it just helpful in handling device rotation and such?



  • shawnshawn CAMember

    We have a universal app where all the view controllers and views are created programmatically (i.e. no interface builder). All of our views are created in the view controller's constructor (or ViewDidLoad) and the only thing we do with the view frames during creation is to set the sizes of things that are fixed size for all orientations/devices, all the X and Y coordinates are set to 0. Each view controller has an override for ViewWillLayoutSubviews() where all the X and Y coordinates are set, as well as the sizes of things that change for different orientations/devices. We don't use any of the auto-sizing or auto-positioning support, we just size and position everything ourselves. Also, we don't keep any class level variables regarding sizing and positioning. They're all local variables within the method in which they are used.

    We also use a similar strategy in our custom views. Each view creates its subviews in the constructor/ViewDidLoad and sets their positions in LayoutSubviews().

    Our app is quite large and complex with many view controllers and custom views. It runs on all the current devices and everything works just fine. And yes, we're in the app store, so it all works to Apple's satisfaction too.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    First, LayoutSubviews is a method on UIView, not UIViewController. The corresponding method for UIViewController is ViewWillLayoutSubviews.

    Second, you should never create or destroy views in LayoutSubviews or ViewWillLayoutSubviews. For a view controller the views should be created in ViewDidLoad. For UIViews the subviews should be created in the constructor.

    The layout code should only change the frame or bounds/center of each view.

  • Useful Information. Thanks.

Sign In or Register to comment.