I'm working on some custom UIView-based input controls, and I'm trying to ascertain proper practice for setting up the view. When working with a UIViewController, it's fairly simple to use the loadView
and related viewWill
, viewDid
methods, but when subclassing a UIView, the closest methosds I have are `awakeFromNib
, drawRect
, and layoutSubviews
. (I'm thinking in terms of setup and teardown callbacks.) In my case, I'm setting up my frame and internal views in layoutSubviews
, but I'm not seeing anything onscreen.
What is the best way to ensure that my view has the correct height and width that I want it to have? (My question applies regardless of if I'm using autolayout, although there might be two answers.) What's the proper "best practice"?
This still comes up high in Google. Below is an updated example for swift.
The
didLoad
function lets you put all your custom initialization code. As others have mentioned,didLoad
will be called when a view is created programmatically viainit(frame:)
or when the XIB deserializer merges a XIB template into your view viainit(coder:)
Apple defined pretty clearly how to subclass
UIView
in the doc.Check out the list below, especially take a look at
initWithFrame:
andlayoutSubviews
. The former is intended to setup the frame of yourUIView
whereas the latter is intended to setup the frame and the layout of its subviews.Also remember that
initWithFrame:
is called only if you are instantiating yourUIView
programmatically. If you are loading it from a nib file (or a storyboard),initWithCoder:
will be used. And ininitWithCoder:
the frame hasn't been calculated yet, so you cannot modify the frame you set up in Interface Builder. As suggested in this answer you may think of callinginitWithFrame:
frominitWithCoder:
in order to setup the frame.Finally, if you load your
UIView
from a nib (or a storyboard), you also have theawakeFromNib
opportunity to perform custom frame and layout initializations, since whenawakeFromNib
is called it's guaranteed that every view in the hierarchy has been unarchived and initialized.From the doc of
NSNibAwaking
It's also worth noting that with autolayout you shouldn't explicitly set the frame of your view. Instead you are supposed to specify a set of sufficient constraints, so that the frame is automatically calculated by the layout engine.
Straight from the documentation:
layoutSubviews
is meant to set frame on child views, not on the view itself.For
UIView
, the designated constructor is typicallyinitWithFrame:(CGRect)frame
and you should set the frame there (or ininitWithCoder:
), possibly ignoring passed in frame value. You can also provide a different constructor and set the frame there.There's a decent summary in the Apple documentation, and this is covered well in the free Stanford course available on iTunes. I present my TL;DR version here:
If your class mostly consists of subviews, the right place to allocate them is in the
init
methods. For views, there are two differentinit
methods that could get called, depending on if your view is being instantiated from code or from a nib/storyboard. What I do is write my ownsetup
method, and then call it from both theinitWithFrame:
andinitWithCoder:
methods.If you're doing custom drawing, you indeed want to override
drawRect:
in your view. If your custom view is mostly a container for subviews, though, you probably won't need to do that.Only override
layoutSubViews
if you want to do something like add or remove a subview depending on if you're in portrait or landscape orientation. Otherwise, you should be able to leave it alone.