4

I would like to align a button in the toolbar of an os x app to the position of a split view in the window, similar to the delete button in Apple Mail. How can this be done using auto layout constraints?

I did find a hint in apples documentation according to which it should be possible to use auto layout constraints (at https://developer.apple.com/library/ios/documentation/userexperience/conceptual/AutolayoutPG/AutoLayoutConcepts/AutoLayoutConcepts.html), where it says that "Constraints can, with some restrictions, cross the view hierarchy. In the Mail app in OS X, for example, by default the Delete button in the toolbar lines up with the message table". But that is unfortunately all I could find.

I tried to create a constraint between the content of the left splitView pane and the button:

NSView *button = self.toolbarItemButton.view;
NSView *leftPane = self.leftSplitContent;

[self.window.contentView addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"[leftPane][button]"
    options:0 metrics:nil
    views:NSDictionaryOfVariableBindings(leftPane, button)]
];

But I then get an error message that seems to indicate that cross-view constraints are not possible: "constraint references something from outside the subtree of the view" Is there any way to do this?

A workaround I found was to not use constraints, but instead insert a custom view (not a spacer!) to the left of the button. I can then change the size of that view to move the button... However, this seems more like a hack to me.

powerpete
  • 160
  • 1
  • 11
  • If you ever figure this out, I'd love to know the secret. As far as adding a custom view to the left of the button, are you just setting the frame value of this "spacer" view every time the split view resizes its subviews, or have you gotten constraints installed somehow? – Ben Stock Nov 07 '14 at 17:00
  • @BenStock Yes, I am setting the frame value every time the split view resizes its subviews. No constraints are used for this. I kind of gave up on finding a better solution, but maybe Yosemite has something to offer? I remember one of the WWDC '14 videos talking about some new toolbar features, so maybe Apple also improved the constraints handling... Might have another look. – powerpete Dec 02 '14 at 22:30

2 Answers2

1

I know it's a bit old, but I had the same issue and found an answer:

You have to use topLayoutGuide property.

Ex in swift

view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormats(
        ["H:|[toolbarShadow]|", "V:[topLayoutGuide][toolbarShadow(100)]"], 
views: viewDictionnary))

Of course topLayoutGuide must be in your view dictionary

You can access it through self.topLayoutGuide

Antzi
  • 12,831
  • 7
  • 48
  • 74
  • What is `toolbarShadow`? – LShi Sep 28 '15 at 09:30
  • @LS.Shanghai You can replace it by anything. I used the constraint to place a shadow on the toolbar, and provided the code without modification here. – Antzi Sep 28 '15 at 10:42
1

I just run into the same question. As in OS X 10.11 El Capitan, we can use NSLayoutGuide for this.

First you should have a reference to the NSView subclass's instance to be aligned to in the "current" source code file. In this case, a subview in your splitview.

This following example is to show how to align two views using NSLayoutAnchor. You may also add vertical constrains to the toolbar item.

- (void) setUpToolbarItemConstrains {

// the view you want your toolbaritem to align to
NSView * refView = self.theOtherView.view;

// theToolbarItem is the outlet to the ToolbarItem
NSView * toolsView = self.theToolbarItem.view;

// You can also do this in Interface Builder
self.theToolbarItem.minSize = CGSizeMake(200.0f, 0.0f);
self.theToolbarItem.maxSize = CGSizeMake(600.0f, 100.0f);

toolsView.translatesAutoresizingMaskIntoConstraints = NO;

[toolsView.leadingAnchor constraintEqualToAnchor: refView.leadingAnchor].active = YES;

}

However, I have an extended question related to this.

Community
  • 1
  • 1
LShi
  • 1,500
  • 16
  • 29