Using interface builder you can select the corners an object should stick to when resizing. How can you do this programatically?
4 Answers
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];
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:
@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.