21
votes

Using interface builder you can select the corners an object should stick to when resizing. How can you do this programatically?

Interface Builder

4
Please note that Apple introduced an AutoLayout framework for Lion.JJD

4 Answers

30
votes

I find that the autoresizingBit masks are horribly named, so I use a category on NSView to make things a little more explicit:

// MyNSViewCategory.h:
@interface NSView (myCustomMethods)

- (void)fixLeftEdge:(BOOL)fixed;
- (void)fixRightEdge:(BOOL)fixed;
- (void)fixTopEdge:(BOOL)fixed;
- (void)fixBottomEdge:(BOOL)fixed;
- (void)fixWidth:(BOOL)fixed;
- (void)fixHeight:(BOOL)fixed;

@end


// MyNSViewCategory.m:
@implementation NSView (myCustomMethods)

- (void)setAutoresizingBit:(unsigned int)bitMask toValue:(BOOL)set
{
    if (set)
    { [self setAutoresizingMask:([self autoresizingMask] | bitMask)]; }
    else
    { [self setAutoresizingMask:([self autoresizingMask] & ~bitMask)]; }
}

- (void)fixLeftEdge:(BOOL)fixed
{ [self setAutoresizingBit:NSViewMinXMargin toValue:!fixed]; }

- (void)fixRightEdge:(BOOL)fixed
{ [self setAutoresizingBit:NSViewMaxXMargin toValue:!fixed]; }

- (void)fixTopEdge:(BOOL)fixed
{ [self setAutoresizingBit:NSViewMinYMargin toValue:!fixed]; }

- (void)fixBottomEdge:(BOOL)fixed
{ [self setAutoresizingBit:NSViewMaxYMargin toValue:!fixed]; }

- (void)fixWidth:(BOOL)fixed
{ [self setAutoresizingBit:NSViewWidthSizable toValue:!fixed]; }

- (void)fixHeight:(BOOL)fixed
{ [self setAutoresizingBit:NSViewHeightSizable toValue:!fixed]; }

@end

Which can then be used as follows:

[someView fixLeftEdge:YES];
[someView fixTopEdge:YES];
[someView fixWidth:NO];
19
votes

See the setAutoresizingMask: method of NSView and the associated resizing masks.

8
votes

Each view has the mask of flags, controlled by setting a the autoresizingMask property with the OR of the behaviors you want from the resizing masks. In addition, the superview needs to be configured to resize its subviews.

Finally, in addition to the basic mask-defined resizing options, you can fully control the layout of subviews by implementing -resizeSubviewsWithOldSize:

3
votes

@e.James answer gave me an idea to simply create a new enum with more familiar naming:

typedef NS_OPTIONS(NSUInteger, NSViewAutoresizing) {
    NSViewAutoresizingNone                 = NSViewNotSizable,
    NSViewAutoresizingFlexibleLeftMargin   = NSViewMinXMargin,
    NSViewAutoresizingFlexibleWidth        = NSViewWidthSizable,
    NSViewAutoresizingFlexibleRightMargin  = NSViewMaxXMargin,
    NSViewAutoresizingFlexibleTopMargin    = NSViewMaxYMargin,
    NSViewAutoresizingFlexibleHeight       = NSViewHeightSizable,
    NSViewAutoresizingFlexibleBottomMargin = NSViewMinYMargin
};

Also, from my research, I discovered that @James.s has a serious bug in the NSView additions. The coordinate system in Cocoa has a flipped y-axis in terms of iOS coordinates system. Hence, in order to fix the bottom and top margin, you should write:

- (void)fixTopEdge:(BOOL)fixed
{ [self setAutoresizingBit:NSViewMaxYMargin toValue:!fixed]; }

- (void)fixBottomEdge:(BOOL)fixed
{ [self setAutoresizingBit:NSViewMinYMargin toValue:!fixed]; }

From the cocoa docs:

NSViewMinYMargin

The bottom margin between the receiver and its superview is flexible.
Available in OS X v10.0 and later.