OS X Stack Views with NSStackView

In this tutorial you will learn how to use stack views to design your OS X app’s layout by leveraging the power of NSStackView. By Marin Todorov.

Leave a rating/review
Save for later
Share
You are currently viewing page 3 of 4 of this article. Click here to view the first page.

Using Constraints on Arranged Views

Stack views give you the power of Auto Layout without the hassle of creating all the constraints yourself, but you can still design constraints manually if you want. And sometimes, you do want to do that; sometimes default settings just don’t work. :]

There’s a few small issues with your layout that would benefit from a few constraints.

Select the Buy now from raywenderlich.com button and click the Pin button at the bottom of Interface Builder. From the popup menu, click the checkbox next to width and enter 250 in the box.

022_width_const

Click Add 1 Constraint to make it so. You’re setting the button width to 250 points, giving it nice padding on the sides so it’s easy on the eyes.

Adding custom constraints is that easy!

How about you align the window contents to the top of the window? Start by selecting your current top stack view.

030_selected_top_stack

In Attributes Inspector, set alignment to Top. This should move the book details views up the window, like so:

031_top_align

Now you’re going to add a bit of spacing on the top so that the cover image is not “stuck” to the window title bar. Select the stack containing the book details (second down the hierarchy):

032_selected_second_stack

Click the Pin button and add a Top constraint with the value of 20 points:

033_top_constraint

Click Add 1 Constraint, and you’ll see that the book details stack view now has 20 points as a top margin.

034_small_window

As you see, you can leave stacks to apply the default behavior and just add a constraint here and there to customize and perfect the layout!

Working with the Arranged Views

Now that you know how to stack up your layouts, the next level is to play around with the stack contents.

The stack view itself is just a container and displays nothing on screen. It merely arranges the layout of a bunch of views, and you can access those via the arrangedSubviews property. For each arranged view, you can show and hide, animate, or remove it from the stack at will.

Stack View Animations

In this last section you’re going to learn the basics of working with arranged subviews.

First of all, in order to access your stack view from code, you need to create an outlet for it. Open ViewController.swift and add a new outlet variable to the class:

@IBOutlet weak var topStack: NSStackView!

Now switch back to Main.storyboard and drag from your ViewController to the top stack view in the document outline while pressing Command on your keyboard:

035_connect_outlet

From the popup menu, select topStack, and voila! Your stack outlet is connected.

Note: Now that you have a live outlet to the stack view you can work with it from code in the same manner you do for labels, button, and other Cocoa controls. For example you can dynamically add arranged view by calling the addArrangedSubview(_:) method on your stack view or remove and arranged view by making use of removeArrangedSubview(_:).

Note: Now that you have a live outlet to the stack view you can work with it from code in the same manner you do for labels, button, and other Cocoa controls. For example you can dynamically add arranged view by calling the addArrangedSubview(_:) method on your stack view or remove and arranged view by making use of removeArrangedSubview(_:).

Run the app and check the button in the top-right corner of the window:

036_menu_button

The menu button is selected by default, but if you click it repeatedly you’ll see it toggles between selected and deselected states. The button is already connected to the method in ViewController called actionToggleListView(_:), so you can just add your code at the bottom of the method body.

First, add an empty animation at the bottom of the method:

NSAnimationContext.runAnimationGroup({context in
  //configure the animation context
  context.duration = 0.25
  context.allowsImplicitAnimation = true

  //perform the animation

}, completionHandler: nil)

runAnimationGroup() allows you create UI animations by simply listing the desired changes in the argument closure. The animations closure gets one parameter, which is the animation context – you can adjust various aspects of the animation by changing the properties on the context. So far you set the animations duration and you enable implicit animations.

Note: Unlike on iOS, in OSX there are different (but similar in effect) APIs to create animations. I personally like using NSAnimationContext.runAnimationGroup(_) because it’s the closest to what I’m using on iOS and can write my code easier and faster by just using the same approach on both platforms.

Note: Unlike on iOS, in OSX there are different (but similar in effect) APIs to create animations. I personally like using NSAnimationContext.runAnimationGroup(_) because it’s the closest to what I’m using on iOS and can write my code easier and faster by just using the same approach on both platforms.

Next you can just toggle the visibility of the first arranged view of the top stack — more specifically, the table view that shows the list of books. To make all changes in the window layout animate nicely, also add a call to layoutSubtreeIfNeeded().

Just below the comment //perform the animation (but still inside the closure) insert this:

self.topStack.arrangedSubviews.first!.hidden = button.tag==0 ? true : false
self.view.layoutSubtreeIfNeeded()

This will hide or show the book list each time you click the button. Since you made your changes from within an animation block, the layout flows nicely to accommodate your changes.

Note: Just like with any other animation under Auto Layout you need to force a layout pass from inside the animations block to animate the changes you do to your views. In fact changing the hidden property on your first arranged view will be automatically animated, the rest of the arranged views however will have to change position and you’d like to animated those changes. That’s why at the end of the block you make a call to layoutSubtreeIfNeeded().

Note: Just like with any other animation under Auto Layout you need to force a layout pass from inside the animations block to animate the changes you do to your views. In fact changing the hidden property on your first arranged view will be automatically animated, the rest of the arranged views however will have to change position and you’d like to animated those changes. That’s why at the end of the block you make a call to layoutSubtreeIfNeeded().

And there you have the completed raywenderlich.com book store project!

Figure4_1

For kicks, choose your favorite book from the list and click on the purchase button. This will open your default web browser and take you directly to the book store page:

038_webshop