3
votes

To allow for flexible layouts, I wanted to create a subclass UIView that overrides layoutSubviews: to layout all of its subviews under each other automagically and would continue to do this every time one of its subviews got resized.

However, the only way that I can think of to let the superview know that it should call layoutSubviews: is by overriding that method in each of its subviews, something that I would like to try and avoid (I want people to be able to add arbitrary UIViews to the superview and have this taken care of).

Is there a way for the superview to call layoutSubviews: whenever a subview changes its size, without adding any code to the subview in question?

2

2 Answers

0
votes

You can add a category to the class and try overriding layoutSubviews: from within the category. (This technique has been suggested for customizing navigation bars, and it may well work here too.)

Here's how you'd make a category, taken from my answer here. In your case, remember to substitute UIView for UINavigationController.

Hit Command+N or open the "New File" dialog. Next, choose "Objective-C category" from the Cocoa Touch menu:

Creating a category

Click Next and you will be prompted to enter the name of the class that you would like to add methods to as a category. It should look something like this:

Making a Category on the NavBar

Then, you should end up with a save file dialog. A quick note about convention here. Convention is to name a category after the original class, the plus sign, and then a description of what you're adding. Here's what yours might look like:

Category Naming Convention

Once you save your file, you will need get something like this:

Empty Category

Edit:

If you want to go ahead and do this without a category, then your best bet is to make a subclass of UIView and then subclass that class wherever you want your custom behavior. Another advantage over a category is that your method will only work where you explicitly use the custom class. In categories, the method gets added everywhere.

Good luck!

0
votes

You could use KVO to observe the frame property of each of your subviews. You would need to add yourself as an observer each time a subview is added and remove the observation when a subview is removed – you can override didAddSubview: and willRemoveSubview: in your superview to do that.

- (void)didAddSubview:(UIView *)subview {
    [subview addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];
}

- (void)willRemoveSubview:(UIView *)subview {
    [subview removeObserver:self forKeyPath:@"frame"];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:@"frame"]) {
         // Do your layout here...
    }
}

- (void)dealloc {
    // You might need to remove yourself as an observer here, in case
    // your subviews are still used by others
}