Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I programmatically position a view using relative points?

What is the best way to position a view relative to the size of its superview, when the bounds of the superview are not yet known?

I am trying to avoid hard-coding coordinates if it is at all possible. Perhaps this is silly, and if so, that's a perfectly acceptable answer.

I've run into this many times when working with custom UI. The most recent example is that I'm trying to replace the UINavigationItem plain-text title with a custom view. I want that view to fill the superview, but in addition, I want a UIActivityIndicatorView on the right side, inset about 2 pixels and centered vertically. Here's the code:

- (void) viewDidLoad
{
    [super viewDidLoad];

    customTitleView = [[UIView alloc] initWithFrame:CGRectZero];
    customTitleView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;

    titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
    titleLabel.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    titleLabel.lineBreakMode = UILineBreakModeWordWrap;
    titleLabel.numberOfLines = 2;
    titleLabel.minimumFontSize = 11.0;
    titleLabel.font = [UIFont systemFontOfSize:17.0];
    titleLabel.adjustsFontSizeToFitWidth = YES;
    [customTitleView addSubview:titleLabel];

    spinnerView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
    spinnerView.center = CGPointMake(customTitleView.bounds.size.width - (spinnerView.bounds.size.width / 2) - 2,
                                     customTitleView.bounds.size.height / 2);
    spinnerView.hidesWhenStopped = YES;
    [customTitleView addSubview:spinnerView];

    self.navigationItem.titleView = customTitleView;
    [customTitleView release];
}

Here's my problem: at the time that this code runs, customTitleView.bounds is still zeroes. The auto-resizing mask hasn't had a chance to do its thing yet, but I very much want those values so that I can compute the relative positions of other sub-views (here, the activity indicator).

Is this possible without being ugly?

like image 380
Steve Madsen Avatar asked Oct 15 '22 06:10

Steve Madsen


1 Answers

The only reason customTitleView.bounds has zero width and height is because you've initialized it that way by using CGRectZero. You can initialize the view with any nonzero size and then define its subviews in relation to that arbitrary size. As long as you've defined the autoresizing behaviors of the subviews properly, their layout will be adjusted appropriately when the frame of the superview changes at runtime.

For example:

- (void) viewDidLoad
{
    [super viewDidLoad];

    customTitleView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 100.0f)];
    customTitleView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;

    titleLabel = [[UILabel alloc] initWithFrame:customTitleView.bounds];
    titleLabel.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    titleLabel.lineBreakMode = UILineBreakModeWordWrap;
    titleLabel.numberOfLines = 2;
    titleLabel.minimumFontSize = 11.0;
    titleLabel.font = [UIFont systemFontOfSize:17.0];
    titleLabel.adjustsFontSizeToFitWidth = YES;
    [customTitleView addSubview:titleLabel];
    [titleLabel release];

    spinnerView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
    spinnerView.center = CGPointMake(customTitleView.bounds.size.width - (spinnerView.bounds.size.width / 2) - 2,
                                     customTitleView.bounds.size.height / 2);
    spinnerView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
    spinnerView.hidesWhenStopped = YES;
    [customTitleView addSubview:spinnerView];
    [spinnerView release];

    self.navigationItem.titleView = customTitleView;
    [customTitleView release];
}
like image 167
cduhn Avatar answered Oct 18 '22 16:10

cduhn