September 11, 2012

Obj-C: Center a view horizontally with autoresizingMask properties

Cocoa's UIView layout system gives the developer some nice tools to automatically resize and reposition views inside of each other. This is usually done in the nib/xib/storyboard editor with the Origin/Autoresizing View property inspectors, and honestly it's never made a ton of sense to me. I'm only an occasional obj-c dev, so bear with me. I wanted to horizontally center and fill some UIView elements to fit the width of different devices and orientations, and I knew there should be a simple way to accomplish this. I came up with several methods to help apply these settings to any number of outer containers that should fill the width of the parent view, and inner containers that should be centered within:
- (void)setViewCentered:(UIView*)view
{
    view.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin);
}

- (void)setContainerToParentWidth:(UIView*)view
{
    view.autoresizingMask = UIViewAutoresizingFlexibleWidth;
}

- (int)getHorizCenterFromView:(UIView*)view
{
    return (self.view.bounds.size.width - view.frame.size.width)/2;
}

- (int)getHorizCenterFromInt:(int)width
{
    return (self.view.bounds.size.width - width)/2;
}
The key to centering a fixed-width view - this was the confusing part for me - is setting the x-position of the frame to 1/2 of the width of the parent container. The associated example call to center a view is here. From my researching, it seems that the autoresizingMask property should be changed after addSubview
    int viewW = 320;
    _controlsContainer = [[UIView alloc] initWithFrame:CGRectMake([self getHorizCenterFromInt:viewW], 0, viewW, controlsH)];
    [self.view addSubview:_controlsContainer];
    [self setViewCentered:_controlsContainer];
Note that self.view is the outer container that we're centering inside of. Then if you simply want to fill a container to the width of the parent, use something like this:
    _header = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];
    [self.view addSubview:_header];
    [self setContainerToParentWidth:_header];
Happy centering without having to change a UIView's frame!