Reputation: 3090
I want to create a NSView container such that any NSControl object added should be right aligned.
I have added a method to MyCustomNSView class as following. Currently I am adding buttons which are getting left aligned.
- (void) _addButton:(NSString *)title withIdentifier:(NSString *)identifier {
NSButton *button = [[NSButton alloc] initWithFrame:NSMakeRect(100 * [_buttonIdentifierList count] + 10 , 5, 70, 20)];
[button setTitle:title];
[button setAction:@selector(actionButtonPressed:)];
[button setTarget:self];
[button setIdentifier:identifier];
[self addSubview:button];
[_buttonIdentifierList addObject:identifier];
}
So what modifications do I have to make to the above method so that it will add the objects from right side.
I was planning to do it mathematically(Generating frame origin that would generate right aligned origin point). I also tried out using NSLayoutConstrains but didnt work out..
How do I do it using autolayouts ?
Upvotes: 0
Views: 273
Reputation: 90681
To do it by manual positioning, you would compute the frame for the button something like this:
NSButton *button = [[NSButton alloc] initWithFrame:NSMakeRect(NSMaxX(self.bounds) - (100 * [_buttonIdentifierList count] + 10) - 70, 5, 70, 20)];
That is, you take your current calculation which is an offset toward the right (from the left edge) and negate it to make it an offset toward the left. You add the value of the right edge of the containing view so it's an offset from the right edge. That has computed the X position of the right edge of the button, so you subtract the button's width to get the origin of the button, which is on its left edge.
To use auto layout (which uses NSLayoutConstraint
), you could do this:
NSButton *button = [[NSButton alloc] initWithFrame:NSZeroRect];
[button setTitle:title];
[button setAction:@selector(actionButtonPressed:)];
[button setTarget:self];
[button setIdentifier:identifier];
button.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:button];
__block NSButton* previousButton = nil;
if (_buttonIdentifierList.count)
{
NSString* previousButtonIdentifier = _buttonIdentifierList.lastObject;
[self.subviews enumerateObjectsUsingBlock:^(NSView* subview, NSUInteger idx, BOOL *stop){
if ([subview.identifier isEqualToString:previousButtonIdentifier])
{
previousButton = (NSButton*)subview;
*stop = YES;
}
}];
}
NSDictionary* metrics = @{ @"buttonWidth": @70,
@"buttonHeight": @20,
@"buttonSeparation": @30,
@"horizontalMargin": @10,
@"verticalMargin": @5 };
if (previousButton)
{
NSDictionary* views = NSDictionaryOfVariableBindings(button, previousButton);
NSArray* constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"[button(buttonWidth)]-(buttonSeparation)-[previousButton]" options:NSLayoutFormatAlignAllBaseline metrics:metrics views:views];
[self addConstraints:constraints];
}
else
{
NSDictionary* views = NSDictionaryOfVariableBindings(button);
NSArray* constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"[button(buttonWidth)]-(horizontalMargin)-|" options:0 metrics:metrics views:views];
[self addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[button(buttonHeight)]-(verticalMargin)-|" options:0 metrics:metrics views:views];
[self addConstraints:constraints];
}
[_buttonIdentifierList addObject:identifier];
Finding the previousButton
would be simplified if you keep track of the buttons, rather than the identifiers. If you have a button object, it's easy to get its identifier, but the reverse (getting the button object when all you have is the identifier) is not as simple.
If you want to allow the buttons to be their natural width and height, rather than a fixed value, you can just leave out those width/height specifiers (that is, use [button]
rather than [button(buttonWidth)]
). If you want all of the buttons to have the same width, but let the system pick the width of the naturally widest button, you can use [button(==previousButton)]
. Since a button's default compression resistance priority is higher than its content hugging priority, it will pick the smallest width that doesn't compress any of them.
If you want the buttons to be the standard distance away from each other, rather than the fixed value of 30 points, you can use use -
instead of -(buttonSeparation)-
. Similarly, if you want them to be the standard distance from the superview edge, you can use -
instead of -(horizontalMargin)-
or -(verticalMargin)-
.
Upvotes: 2