Mar 06, 2014  One of our latest iOS projects has quite a few view controllers. A few weeks ago, John Fisher wrote about the pain of large storyboards and our solution of using multiple storyboards, but we’ve found an even better solution.This technique is more reliable, easier to use and has less code.

-->

A storyboard defines all of the UI for a given app broken down into a functional overview of its view controllers. In Xcode's Interface Builder, each of these controllers lives in its own Scene.

The storyboard is a resource file (with the extensions of .storyboard) that gets included in the Xamarin.Mac app's bundle when it is compiled and shipped. To define the starting Storyboard for your app, edit it's Info.plist file and select the Main Interface from the dropdown box:

Loading from Code

There might be times when you need to load a specific Storyboard from code and create a View Controller manually. You can use the following code to perform this action:

The FromName loads the Storyboard file with the given name that has been included in the app's bundle. The InstantiateControllerWithIdentifier creates an instance of the View Controller with the given Identity. You set the Identity in Xcode's Interface Builder when designing the UI:

Optionally, you can use the InstantiateInitialController method to load the View Controller that has been assigned the Initial Controller in Interface Builder:

It's marked by the Storyboard Entry Point and the open ended arrow above.

View Controllers

View Controllers define the relationships between a given View of information within a Mac app and the data model that provides that information. Each top level scene in the Storyboard represents one View Controller in the Xamarin.Mac app's code.

The View Controller Lifecycle

Using Storyboards For Os X

Several new methods have been added to the NSViewController class to support Storyboards in macOS. Most importantly are the follow methods use to respond to the lifecycle of the View being controlled by the given View Controller:

  • ViewDidLoad - This method is called when the view is loaded from the Storyboard file.
  • ViewWillAppear - This method is called just before the view is displayed on screen.
  • ViewDidAppear - This method is called directly after the view has been displayed on screen.
  • ViewWillDisappear - This method is called just before the view is removed from the screen.
  • ViewDidDisappear - This method is called directly after the view has been removed from the screen.
  • UpdateViewConstraints - This method is called when the constraints that define a view auto layout position and size need to be updated.
  • ViewWillLayout - This method is called just before the subviews of this view are laid out on screen.
  • ViewDidLayout - This method is called directly after the subviews of view are laid out on screen.

The Responder Chain

Additionally, NSViewControllers are now part of the Window's Responder Chain:

And as such they are wired-up to receive and respond to events such as Cut, Copy and Paste menu item selections. This automatic View Controller wire-up only occurs on apps running on macOS Sierra (10.12) and greater.

Containment

In Storyboards, View Controllers (such as the Split View Controller and the Tab View Controller) can now implement Containment, such that they can 'contain' other sub View Controllers:

Child View Controllers contain methods and properties to tie them back to their Parent View Controller and to work with displaying and removing Views from the screen.

All Container View Controllers built into macOS have a specific layout which Apple suggest that you follow if creating your own custom Container View Controllers:

The Collection View Controller contains an array of Collection View Items, each of which contain one or more View Controllers that contain their own Views.

Segues

Segues provide the relationships between all of the Scenes that define your app's UI. If you are familiar with working in Storyboards in iOS, you know that Segues for iOS usually define transitions between full screen views. This differs from macOS, when Segues usually define 'Containment', where one Scene is the child of a parent Scene.

In macOS, most apps tend to group their views together within the same window using UI elements such as Split Views and Tabs. Unlike iOS, where views need to be transitioned on and off screen, due to limited physical display space.

Presentation Segues

Given macOS's tendencies towards containment, there are situations where Presentation Segues are used, such as Modal Windows, Sheet Views and Popovers. macOS Provides the following built-in segue types:

  • Show - Displays the target of the Segue as a non-modal window. For example, use this type of Segue to present another instance of a Document Window in your app.
  • Modal - Presents the target of the Segue as a modal window. For example, use this type of Segue to present the Preferences Window for your app.
  • Sheet - Presents the target of the Segue as a Sheet attached to the parent window. For example, use this type of segue to present a Find and Replace Sheet.
  • Popover - Presents the target of the Segue as in a popover window. For Example, use this Segue type to present options when a UI element is clicked by the user.
  • Custom - Presents the target of the Segue using a custom Segue Type defined by the developer. See the Creating Custom Segues section below for more details.

When using Presentation Segues, you can override the PrepareForSegue method of the parent View Controller for presentation to initialize and variables and provide any data to the View Controller being presented.

Triggered Segues

Triggered Segues allow you to specify named Segues (via their Identifier property in Interface Builder) and have them triggered by events such as the user clicking a button or by calling the PerformSegue method in code:

The Segue ID is defined inside of Xcode's Interface Builder when you are laying out the app's UI:

In the View Controller that is acting as the source of the Segue, you should override the PrepareForSegue method and do any initialization required before the Segue is executed and the specified View Controller is displayed:

Optionally, you can override the ShouldPerformSegue method and control whether or not the Segue is actually executed via C# code. For manually presented View Controllers, call their DismissController method to remove them from display when they are no longer needed.

Creating Custom Segues

There might be times when your app requires a Segue type not provided by the build-in Segues defined in macOS. If this is the case, you can create a Custom Segue that can be assigned in Xcode's Interface Builder when laying out your app's UI.

Using Storyboards For Os X Download

For example, to create a new Segue type that replaces the current View Controller inside a Window (instead of opening the target Scene in a new window), we can use the following code:

A couple of things to note here:

  • We are using the Register attribute to expose this class to Objective-C/macOS.
  • We are overriding the Perform method to actually perform the action of our custom Segue.
  • We are replacing the Window's ContentViewController controller with the one defined by the target (destination) of the Segue.
  • We are removing the original View Controller to free up memory using the RemoveFromParentViewController method.

To use this new Segue type in Xcode's Interface Builder, we need to compile the app first, then switch to Xcode and add a new Segue between two scenes. Set the Style to Custom and the Segue Class to ReplaceViewSegue (the name of our custom Segue class):

Window Controllers

Window Controllers contain and control the different Window types that your macOS app can create. For Storyboards, they have the following features:

  1. They must provide a Content View Controller. This will be the same Content View Controller that the child Window has.
  2. The Storyboard property will contain the Storyboard that the Window Controller was loaded from, else null if not loaded from a Storyboard.
  3. You can call the DismissController method to close the given Window and remove it from view.

Like View Controllers, Window Controllers implement the PerformSegue, PrepareForSegue and the ShouldPerformSegue methods and can be used as the source of a Segue operation.

Window Controller are responsible for the following features of a macOS app:

  • They manage a specific Window.
  • They manage the Window's Title Bar and Toolbar (if available).
  • They manage the Content View Controller to display the contents of the Window.

Gesture Recognizers

Gesture Recognizers for macOS are nearly identical to their counterparts in iOS and allow the developer to easily add gestures (such as clicking a mouse button) to elements in your app's UI.

However, where gestures in iOS are determined by the app's design (such as tapping the screen with two fingers), most gestures in macOS are determined by hardware.

By using Gesture Recognizers, you can greatly reduce the amount of code required to add custom interactions to an item in the UI. As they can automatically determine between double and single clicks, click and drag events, etc.

Instead of overriding the MouseDown event in your View Controller, you should be using a Gesture Recognizer to handle the user input event when working with Storyboards.

The following Gesture Recognizers are available in macOS:

  • NSClickGestureRecognizer - Register mouse down and up events.
  • NSPanGestureRecognizer - Registers mouse button down, drag and release events.
  • NSPressGestureRecognizer - Registers holding a mouse button down for a given amount of time event.
  • NSMagnificationGestureRecognizer - Registers a magnification event from trackpad hardware.
  • NSRotationGestureRecognizer - Registers a rotation event from trackpad hardware.

Using Storyboard References

A Storyboard Reference allows you to take a large, complex Storyboard design and break it into smaller Storyboards that get referenced from the original, thus removing complexity and making the resulting individual Storyboards easier to design and maintain.

Additionally, a Storyboard Reference can provide an anchor to another scene within the same Storyboard or a specific scene on a different one.

Referencing an External Storyboard

To add a reference to an external Storyboard, do the following:

  1. In the Solution Explorer, right-click on the Project Name and select Add > New File... > Mac > Storyboard. Enter a Name for the new Storyboard and click the New button:

  2. In the Solution Explorer, double-click the new Storyboard name to open it for editing in Xcode's Interface Builder.

  3. Design the layout of the new Storyboard's scenes as you normally would and save your changes:

  4. Switch to the Storyboard that you are going to be adding the reference to in the Interface Builder.

  5. Drag a Storyboard Reference from the Object Library onto the Design Surface:

  6. In the Attribute Inspector, select the name of the Storyboard that you created above:

  7. Control-click on a UI Widget (like a Button) on an existing Scene and create a new Segue to the Storyboard Reference that you just created. From the popup menu select Show to complete the Segue:

  8. Save your changes to the Storyboard.

  9. Return to Visual Studio for Mac to sync your changes.

When the app is run and the user clicks on the UI element that you created the Segue from, the Initial Window Controller from the External Storyboard specified in the Storyboard Reference will be displayed.

Referencing a Specific Scene in an External Storyboard

To add a reference to a specific Scene an external Storyboard (and not the Initial Window Controller), do the following:

  1. In the Solution Explorer, double-click the external Storyboard to open it for editing in Xcode's Interface Builder.

  2. Add a new Scene and design its layout as you normally would:

  3. In the Identity Inspector, enter a Storyboard ID for the new Scene's Window Controller:

  4. Open the Storyboard that you are going to be adding the reference to in Interface Builder.

  5. Drag a Storyboard Reference from the Object Library onto the Design Surface:

  6. In the Identity Inspector, select the name of the Storyboard and the Reference ID (Storyboard ID) of the Scene that you created above:

  7. Control-click on a UI Widget (like a Button) on an existing Scene and create a new Segue to the Storyboard Reference that you just created. From the popup menu select Show to complete the Segue:

  8. Save your changes to the Storyboard.

  9. Return to Visual Studio for Mac to sync your changes.

When the app is run and the user clicks on the UI element that you created the Segue from, the Scene with the given Storyboard ID from the External Storyboard specified in the Storyboard Reference will be displayed.

Referencing a Specific Scene in the Same Storyboard

To add a reference to a specific Scene the same Storyboard, do the following:

  1. In the Solution Explorer, double-click the Storyboard to open it for editing.

  2. Add a new Scene and design its layout as you normally would:

  3. In the Identity Inspector, enter a Storyboard ID for the new Scene's Window Controller:

  4. Drag a Storyboard Reference from the Toolbox onto the Design Surface:

  5. In Attribute Inspector, select Reference ID (Storyboard ID) of the Scene that you created above:

  6. Control-click on a UI Widget (like a Button) on an existing Scene and create a new Segue to the Storyboard Reference that you just created. From the popup menu select Show to complete the Segue:

  7. Save your changes to the Storyboard.

  8. Return to Visual Studio for Mac to sync your changes.

When the app is run and the user clicks on the UI element that you created the Segue from, the Scene with the given Storyboard ID in the same Storyboard specified in the Storyboard Reference will be displayed.

Complex Storyboard Example

For a complex example of working with Storyboards in a Xamarin.Mac app, please see the SourceWriter Sample App. SourceWriter is a simple source code editor that provides support for code completion and simple syntax highlighting.

The SourceWriter code has been fully commented and, where available, links have be provided from key technologies or methods to relevant information in the Xamarin.Mac Guides Documentation.

Related Links

Using Storyboards For Os X 11

-->

This article provides an introduction to working with Storyboards in a Xamarin.Mac app. It covers creating and maintaining the app's UI using storyboards and Xcode's Interface Builder.

Storyboards allow you to develop a User Interface for your Xamarin.Mac app that not only includes the window definitions and controls, but also contains the links between different windows (via segues) and view states.

This article will provide an introduction to using Storyboards to define a Xamarin.Mac app's user Interface.

What are Storyboards?

By using Storyboards, all of a Xamarin.Mac app's UI can be defined in a single location with all of the navigation between its individual elements and user interfaces. Storyboards for Xamarin.Mac, work in a very similar fashion to Storyboards for Xamarin.iOS. However, they contain a different set of Segue Types because of the different interface idioms.

Working with Scenes

As stated above, a Storyboard defines all of the UI for a given app broken down into a functional overview of its View Controllers. In Xcode's Interface Builder, each of these controllers lives in its own Scene.

Each Scene represents a given View and View Controller Pair with a set of lines (called Segues) that connect each Scene in the UI, thus showing their relationships. Some Segues define how one View Controller contains one or more child Views or View Controllers. Other Segues, define transitions between View Controller (such as displaying a popover or dialog box).

The most important thing to note is that each Segue represents the flow of some form of data between the given element of the app's UI.

Working with View Controllers

View Controllers define the relationships between a given View of information within a Mac app and the data model that provides that information. Each top level scene in the Storyboard represents one View Controller in the Xamarin.Mac app's code.

In this way, each View Controller is a self-contained, reusable pairing of both the information's visual representation (View) and the logic to present and control that information.

Within a given Scene, you can do all of the things that would normally have been handled by individual .xib files:

  • Place subviews and controls (such as buttons and text boxes).
  • Define element positions and auto layout constraints.
  • Wire-up Actions and Outlets to expose UI elements to code.

Working with Segues

As stated above, Segues provide the relationships between all of the Scenes that define your app's UI. If you are familiar with working in Storyboards in iOS, you know that Segues for iOS usually define transitions between full screen views. This differs from macOS, when Segues usually define 'containment' (where one Scene is the child of a parent Scene).

In macOS, most apps tend to group their views together within the same window using UI elements such as Split Views and Tabs. Unlike iOS, where views need to be transitioned on and off screen, due to limited physical display space.

Given macOS's tendencies towards containment, there are situations where Presentation Segues are used, such as Modal Windows, Sheet Views and Popovers.

When using Presentation Segues, you can override the PrepareForSegue method of the parent View Controller for presentation to initialize and variables and provide any data to the View Controller being presented.

Design and Run Times

At Design time (when layout out the UI in Xcode's Interface Builder), each element of the app's UI is broken down into it's constituent items:

  • Scenes - Which are composed of:
    • View Controller - That define the relationships between Views and the data that support them.
    • Views and Subviews - The actual elements that make up the user interface.
    • Containment Segues - That define the parent-child relationships between Scenes.
  • Presentation Segues - That define individual presentation modes.

By defining each element in this way, it allows for the lazy-loading of each element only as it is needed during runtime. In macOS, the entire process was designed to allow the developer to create complex, flexible User Interfaces that require a bare minimum of backing code to make them work, all while being as efficient with system resources as possible.

Storyboard Quick Start

In the Storyboard Quick Start guide, we'll create a simple Xamarin.Mac app that introduces the key concepts of working with storyboards to create a User Interface. The sample app will consist of a Spilt View containing a Content Area and an Inspector Area and it will present a simple Preferences Dialog window. We'll be using Segues to tie all of the User Interface elements together.

Working with Storyboards

This section covers the in-depth details of Working with Storyboards in a Xamarin.Mac app. We take an in-depth look at Scenes and how they are composed of View Controllers and View. Then, we'll take a look at how Scenes are tied together with Segues. Finally, we'll take a look at working with custom Segue types.

Complex Storyboard Example

Using Storyboards For Os X 2

For an example of a complex example of working with Storyboards in a Xamarin.Mac app, please see the SourceWriter Sample App. SourceWriter is a simple source code editor that provides support for code completion and simple syntax highlighting.

The SourceWriter code has been fully commented and, where available, links have be provided from key technologies or methods to relevant information in the Xamarin.Mac Guides Documentation.

Using Storyboards For Os X 7

Summary

This article has taken a quick look at working with Storyboards in a Xamarin.Mac app. We saw how to create a new app using storyboards and how to define a user interface. We also saw how to navigate between different windows and view states using segues.

Related Links