Discover the latest advances in Mac app development using AppKit. We'll take you through the latest updates to SF Symbols, show you how you can elevate your interface with enhanced controls, and help you learn to coordinate your windows with Stage Manager. We'll also explore the latest sharing and collaboration features for macOS.
♪ ♪ Jeff Nadeau: Hello, and welcome to What's new in AppKit. I'm Jeff Nadeau, an engineer on the AppKit team, and I'm here to share the latest and greatest in building apps for macOS Ventura. It's never been a more exciting time for the Mac, between the performance and efficiency of Apple Silicon, the power of macOS, and an app ecosystem that's richer than ever. Your apps are an important part of that story, and we're continuing to push AppKit forward so that you can keep building the very best apps.
I'll be covering a wide variety of topics, starting with Stage Manager, moving on to Preferences, followed by controls, SF Symbols, and sharing. I'll start off with Stage Manager.
Stage Manager cleans up inactive windows in your workspace while your active window takes center stage. For a more advanced workflow, you can also pull windows together into sets which swap in and out as a group.
This has an impact on how your app windows present themselves. Stage Manager is trying to keep the working space tidy, so when a new window is presented, existing windows will exit the stage to make room. That's what you want for "primary" windows, like your documents. Auxiliary windows like panels, popovers, settings, and others should continue to appear above the existing windows. NSWindow already has a lot of APIs that can help you define the behavior you'd like for a particular window.
By default, Stage Manager won't swap out other windows if you present a floating panel, a modal window, or a window with a preference-style toolbar.
Stage Manager also respects your window's collectionBehavior. This OptionSet defines how your window behaves in spaces and full screen, and it now also helps Stage Manager understand that a window is considered to be auxiliary or floating.
If a window's collectionBehavior includes the auxiliary, moveToActiveSpace, stationary, or transient options, then it won't displace the active window in center stage.
By setting up your windows with the right collection behaviors, you can make sure that they work great in every context, whether it's a desktop space, full screen, or now in Stage Manager. Next, I'd like to cover some important changes to Preferences. In macOS Ventura, the System Preferences app has taken on a whole new look, with a refreshed navigation scheme and all-new visual design. To align with the settings experience on our other operating systems, we've also renamed the app to System Settings.
These changes extend to your application too. For example, you might have a preference pane bundle that appears in the System Preferences app today. You might also have a settings area inside of your app. There's also a new design system for control-rich forms that may be the perfect fit for settings interfaces or inspectors. If you ship a custom prefpane bundle, it'll continue to work with the new Settings app. Your custom pane will appear in the sidebar, and the app will load up your bundle and present your settings UI just like it did in Monterey and earlier.
To match the newly-renamed System Settings app, we've renamed in-app preferences to "settings" as well. To help get you started, once you build against the newest SDK, AppKit will automatically update the name of the "Preferences," menu item in your app menu. However, you might be using the word "Preferences" in a number of other places, like window titles, descriptive labels, or other controls around your app. Search through your localized text to find places that also need updating.
For example, TextEdit's settings window used to be called "preferences" and we chose to rename that window to Settings to match the rest of the system. The System Settings app also uses a new interface style for presenting all of its configuration options. Settings interfaces are often control-heavy, so this style is designed to present forms containing many controls in a clear and well-organized fashion.
Since the form itself provides a lot of visual structure, many system controls adapt to this context by drawing with a lower visual weight, while revealing more prominent control backings on rollover.
If you want to write interfaces that use this new design, SwiftUI makes it super easy. Place your controls into a Form view, and then apply the "insetGrouped" form style. SwiftUI takes care of the rest: the visual style, scrolling behavior, and layout of the form are all applied automatically.
If you haven't gotten started with SwiftUI yet, this is a great opportunity to give it a try. A Settings window is often a standalone area of your app's interface, so it's the perfect place to do some incremental adoption.
We've even created a video about using SwiftUI and AppKit together, which is a great place to learn more. Next, I'd like to share some updates to our controls. We've got a lot of exciting control enhancements to share, starting with a new control called NSComboButton. We've also updated NSColorWell, made some enhancements to the NSToolbar API, adjusted the design of NSAlert, and improved the performance of NSTableView. First, NSComboButton. NSComboButton is all about combining an immediate button action, and a menu for additional options.
In today's control landscape, you'd traditionally use a button to perform some immediate action, or you would use a pull-down button to show a menu with many options. NSComboButton combines both elements into a single control, which joins a primary action and a pull-down menu together. This design is commonly used for use cases like this one in Mail, where the predicted folder is a single click away, but you can still access a menu to file your messages anywhere. Previously, you might've assembled something like this using the segmented control API, but now there's a dedicated control for it.
NSComboButton comes in two styles, which dictate both the appearance and the behavior of the button. The default style is called "split," and it includes a separate arrow portion just for the menu.
The second style, "unified," looks much more like an ordinary button. This style performs its primary action on click, and it presents its menu if you click-and-hold. And that's NSComboButton. We've also got some great new updates to NSColorWell, starting with a brand-new look. In place of the classic square gradient appearance, the color well has adopted a new style reminiscent of other button bezels across the system. This change is completely automatic, so you don't need to do any adoption to get this modern appearance.
However, we know that color picking is an important part of creative and professional applications, so we've gone a step further and introduced two new styles for NSColorWell.
The first is a minimal style, which shows a disclosure arrow on rollover, and provides a quick color picking experience by showing a popover to immediately select from a palette of colors, with the option to break out into the full NSColorPanel. By default, it uses a system standard grid of colors, but you can customize what appears here if you've got a different UI or palette in mind.
The second is an expanded style, which you might recognize from the iWork apps. This style combines both interaction models: the well on the left has the same disclosure arrow and popover for quick picking, while the button on the right pulls up the full panel for more detailed color picking.
And with that, NSColorWell now offers three different ways to pick colors.
You can access these styles using the new colorWellStyle property on NSColorWell, which has cases for each style: default, expanded, and minimal.
NSColorWell has also gained a new target-and-action pair for its "pulldown action." This action determines what happens when you click the pulldown portion of a minimal or expanded color well. By default, these properties are nil, which signifies that NSColorWell should use the system-standard popover. However, you can customize this action and use it to present your own custom popover, Or you could even present a different picking interface, like a menu. And that's the new NSColorWell. It's got a brand new look and two new ways to quickly pick colors.
Next up, some news on NSToolbar, where we've made a variety of API enhancements to give you better control over customization and increased flexibility for your layout.
On the customization front, we've added two new delegate methods to give you better control over the customizability of your toolbar. The first is "toolbarImmovableItemIdentifiers". If you implement this method to return a set of item identifiers, those items won't be movable or removable by the user, and they won't animate when you enter customization mode.
For example, the Mail app wants the Filter button to always appear here, above the message list. Using this API, they can prevent it from being moved away from this spot.
The second method is called "toolbar itemIdentifier canBeInsertedAt." This delegate method gives you veto power over any particular reordering, insertion, or removal from the toolbar. You can use it to implement your own set of customization rules – for example, you could create a toolbar item that's allowed within one section of the toolbar, but it's disallowed within another section.
You can now specify multiple centered items for your toolbar using the new centeredItemIdentifiers property. If your toolbar is customizable, items in this set can still be added or removed from the toolbar, but they can only be reordered within the centered group. In this example, the photo editing tools all stick together in the center of the toolbar regardless of how many items are placed in the leading and trailing sections.
Once your toolbar is customized the way you like it, you don't want the items to shift around, and that can be difficult for toolbar items that change meaning based on some other state, like the Mute and Unmute button in Mail, which toggles when you click it.
Since the labels have different sizes, the other items in the toolbar have to shift around to accommodate the change.
In a scenario like this, you can use the new possibleLabels property on NSToolbarItem to provide a set of the localized strings that you'll use for the item.
NSToolbar will automatically size the item to fit the longest label, so your layout stays the same even when the item is reconfigured. Next, a design update for alerts. Alerts on macOS use a compact layout, which is optimized for a small amount of text accompanied by a few clear choices. And in general, that's a great way to put together an alert. Alerts work best with shorter text: you can communicate your message more directly, and people are more likely to read what you've written before pushing their way through the alert.
However, sometimes you really can't shorten your description, especially if you need to communicate something complex and subtle, like this Disk Utility alert, which conveys a really important choice about your filesystem data. The compact layout just isn't optimal for this situation. For these cases, we've adapted NSAlert to provide a wider layout that's suitable for longer text. This adaptation happens automatically for alerts where the informative text is too long to fit comfortably in the compact size. We'll also use this style if you have an accessory view that's too large to fit in a compact alert window. There's no need for your app to opt in to this behavior – it's applied automatically system-wide. It's important to note that the layout is determined at the time you present the alert, so an alert won't swap styles if you modify it while it's already on screen.
You should still aim to reduce the length of your alert text wherever possible, but this design update will improve the user experience for those cases where you can't.
Next, an important new feature of NSTableView. NSTableView is designed to efficiently handle a very large number of rows, by lazily populating and reusing the views as you scroll.
However, for tables where each row can have a different height, that can be a challenge, because in order to provide a good scrolling experience the table needs to know its total height and the location of each row in the scrolling region.
Historically, NSTableView does this by sizing all of the rows in the table, which can have an impact on initial load times. In macOS Ventura, NSTableView achieves those goals while providing much better performance.
Instead of eagerly calculating the height for each row, NSTableView now lazily calculates row heights based on which rows are within or near the scrolling viewport.
For the rows that haven't been measured yet, NSTableView uses a running estimated height based on the row heights that it's already measured. As you scroll through the table, NSTableView requests row heights as needed, replacing the estimated heights with real measurements, while taking care to maintain the correct scrolling position.
This optimization significantly improves the load times for very large tables. The change does alter the timing of delegate calls like "table view: height of row", so you shouldn't make assumptions about when NSTableView will request row heights from you.
This optimization applies to both NSTableView and SwiftUI's List view, and it's automatically used for all apps on macOS Ventura with no adoption required. And that's NSTableView performance.
Next, some updates on SF Symbols. macOS Ventura includes SF Symbols 4, which adds more than 450 new symbol images covering all kinds of subjects.
These new symbols include laurels, all kinds of household objects, currency symbols from around the world, and even a variety of sports-related symbols. With a catalog of thousands of symbols, it's likely that SF Symbols includes a professionally-designed icon for any idea that you want to represent. But we haven't stopped there. SF Symbols 4 also includes some new features to further enhance your iconography.
To recap, symbol images support a number of rendering modes that you can choose from depending on your design. There's monochrome, which uses a single color; hierarchical, which uses different opacities of a color to emphasize certain portions of a symbol; palette, which allows you to specify distinct colors for each part of a symbol; and multicolor, which uses colors designed directly into the symbol artwork.
These choices give you the flexibility to realize a wide variety of designs, but we also want symbol images to look their best right out of the box, without the need to apply any configuration.
That's why we've introduced a new feature to symbols in macOS Ventura: preferred rendering mode. With preferred rendering mode, symbols can specify the style of rendering that they prefer, and at runtime AppKit will use that style automatically. This is great for symbols like AirPods Pro, which prefers a hierarchical style to increase the clarity of those fine details. Of course, if you have a different design in mind, you can always use an NSImageSymbolConfiguration object to choose your preferred style.
Some symbols don't just represent a concept, they're also meant to communicate some value or quantity, like your Wi-Fi signal strength, or audio volume. For cases like these, we've introduced a new type of symbol that we call a "variable symbol." With a variable symbol, you supply a floating point value directly to NSImage, and the symbol embeds numeric thresholds to decide how each path should vary based on that value. Here's the API. Variable symbols are created using a new initializer. It's similar to the existing symbol image initializer, with the addition of a value parameter, which is a floating point number between zero and one. If the symbol image doesn't define any variable thresholds, this value is ignored and the symbol draws as it normally would. If it does, you'll see the symbol paths drawing differently based on the value you supplied.
Each variable symbol can represent a value in its own unique way, and by providing that value at the API level, you get access to all of those variations without having to know the fine details of how the symbol is composed.
Variable symbols work great in combination with rendering styles like palette color and multicolor, so you can adapt them to almost any design. Finally, I'd like to cover some big updates to Sharing macOS Ventura elevates the sharing experience on the Mac, introducing features like suggested people and new ways to invite and manage the people that you're collaborating with. There are some new APIs that you can adopt so that your app gets the most out of these enhancements.
The most prominent update to the sharing experience is the new sharing popover. This replaces the existing share menu with a rich interface that includes more information about the document you're sharing and familiar features like suggested people. It supports all of the same APIs and delegate methods as the previous picker, so you can still do things like filter the list of sharing services, or insert your own custom services into the picker.
If you're sharing a file URL, NSSharingServicePicker can automatically populate the header with an icon, name, and other metadata about the file. But if you're sharing a custom type instead, you can conform your items to a new protocol that NSSharingServicePicker will use to request that information.
The protocol is called NSPreviewRepresentableActivityItem. Conforming types must be able to return the underlying item to share, like an NSItemProvider, and they can optionally return a title, an image provider, and an icon provider.
For convenience, there's a conforming class in AppKit called NSPreviewRepresentingActivityItem which you can use to bundle up an existing sharing item with its metadata. You can provide each image parameter directly as an NSImage, or you can use NSItemProvider if it's too performance-intensive to generate those images up front.
The new sharing picker is great for kicking off sharing from somewhere like a toolbar button, but sometimes you want to start sharing from a menu, like the main menu bar or the context menu for a selected view inside your app. Previously, you might've constructed your own menu to handle this, by enumerating sharing services and then building menu items for each one. Although that does work, it bypasses the standard picker, so now you're missing out on all of those new features. In macOS Ventura, NSSharingServicePicker can create a "standardShareMenuItem" for you. You can add the standard item to any menu to easily kick off sharing. Once selected, the menu item summons the sharing popover, and for context menus, it'll even anchor the popover to the same view that produced the menu.
There's a lot of new support for managing collaboration in macOS Ventura.
With some extra adoption, your shareable items can also become invitations to collaborate, which users can initiate via the sharing picker, drag-and-drop into Messages, or even via FaceTime. You can share content using CloudKit or iCloud Drive, or you can connect the invitation flow with your own collaboration server. Now this is a really big topic, so we've made a few videos to explain it in much greater depth. They're a must-see if your app supports collaboration, or if you'd like to get started with adding it. As you get started with macOS Ventura, make sure you're setting up your windows to work best with Stage Manager. Then, consider how your design might benefit from control enhancements like NSComboButton and NSColorWell. Improve your iconography using the newest symbols and features of SF Symbols. And finally, for collaboration, adopt the latest APIs so that you get the most out of macOS Ventura's new sharing experience.
Thanks so much for watching, and thanks for continuing to build great Mac applications.