WWDC 21
What's new in AppKit
Design & control updates
There are design updates for some system controls:
- popovers appear with an animation
- sliders smoothly glide into position when clicked
- smaller things like increased spacing between table sections or slightly wider toolbar buttons
Control tinting:
Individual controls like buttons, segmented controls or sliders can have a custom tint
Properties: NSButton.bezelColor
, NSSegmentedControl.selectedSegmentBezelColor
, NSSlider.trackFillColor
These properties have been introduced in macOS Sierra for Touch Bar controls; in macOS Monterey they’re functional also for normal app controls
This is useful for specific controls that need to have some kind of semantically meaningful color
→ e.g. a green “Accept Call” and a red “End Call” buttons in a video call app
Avoid confusion with the default button if there is one in the same view, since it will also be colorful
Make sure to indicate purpose with more than just the color (using a clear label or an icon), since some of your users may not be able to distinguish buttons by color
Push buttons:
Push buttons no longer highlight using the accent color on click – they behave just like e.g. segmented controls in macOS Big Sur
Don’t make assumptions about how the highlight state looks (e.g. drawing white text over a button that should be blue when pressed, but will now be light gray)
Instead, check the interior background style NSButtonCell.interiorBackgroundStyle
:
.normal
= colorless state.emphasized
= colorful state
The old “regular square button” aka “bevel button” has now been refreshed as “Flexible push style button” and can be used as a variable height push button
It supports the same kind of configuration as a regular push button, so it can serve as a default button and can be tinted
Its corner radius and padding now match other button styles
It can contain larger icons or multi-line text
The vast majority of buttons should still use the standard fixed height push button – the variable height button is meant for special cases
Localizing keyboard shortcuts
Some keyboard shortcuts should be localized for different keyboard layouts, because in some layouts they may be hard or impossible to type, or it may make sense to adapt them for right-to-left languages
E.g. Cmd + \
is not possible to type on the Japanese keyboard, which doesn’t have a backslash key
AppKit can now handle this for you
In macOS Monterey, the system automatically remaps such shortcuts to different ones that are more natural on the given keyboard layout
Shortcuts like Cmd + [
and Cmd + ]
to go back and forward will be swapped in right-to-left languages
→ this applies to brackets, braces, parentheses and arrow keys
You can opt out using:
NSMenuItem.allowsAutomaticKeyEquivalentMirroring
– for directional keys like bracketsNSMenuItem.allowsAutomaticKeyEquivalentLocalization
– turns off all key localization, including mirroring- if you really don’t want to use this feature at all, you can also disable it completely in your app by implementing the
NSApplicationDelegate
method:applicationShouldAutomaticallyLocalizeKeyEquivalents(_:)
Update to SF Symbols
New version – SF Symbols 3
Expands capabilities of the SF Symbols app
Some symbols now have multiple layers that can be individually colored
Updated format for custom symbols – allows you to annotate distinct layers within an image
Big Sur had two coloring modes for symbols:
- traditional monochrome template style, drawing the whole symbol using one accent color
- a multicolor style that uses multiple colors that are predefined in the symbol itself
SF Symbols 3 in macOS Monterey adds two new rendering modes:
- "hierarchical" – uses a single tint color, but draws different layers of the image in an emphasized or deemphasized way (lighter or darker than the base color)
- "palette" – lets you assign each layer any custom color independently
APIs for the new rendering modes:
NSImage.SymbolConfiguration(hierarchicalColor: .red) NSImage.SymbolConfiguration(paletteColors: […]) NSImage.SymbolConfiguration.preferringMulticolor()
Symbol variants:
There are also new APIs for mapping between symbol variants, e.g. outline heart symbol ⭤ filled heart symbol, or variants with circles etc.
Useful e.g. when you’re building a picker control that uses outline icons for unselected states and filled variants of the same icons for the selected item
To convert between variants, call e.g.: baseImage.image(with: .fill)
There are constants for each kind of symbol variant, and you can combine multiple variants together (e.g. circle + fill)
See “Design and build SF Symbols” for more info
TextKit 2
Huge update to the text system
TextKit is a great text engine with a long track record, used across all Apple systems
However, TextKit is a linear text layout engine, which means it typesets a block of text from the beginning to the end
There are a lot of use cases where a non-linear layout engine is more useful
TextKit 2 always uses a non-linear layout system
This means it can perform layout on a more granular level, which allows it to avoid some unnecessary work
For example, when you’re looking at a middle fragment of a long document, a linear layout system needs to process all text from the beginning up to the given fragment in order to render it; a non-linear system can start at the nearest start of a paragraph
The non-linear layout system also makes it easier to mix text with non-text elements, and improves performance for large documents
TextKit 2 provides a lot of customization points, which allow you to extend its behavior
The new version coexists with TextKit 1, you can choose which engine to use for each view
TextKit 2 has actually already been used in some system apps and controls in Big Sur
See “Meet TextKit 2” for more info
New Swift features
Swift 5.5 introduces some important new features for managing concurrency: async/await and actors
In AppKit, many asynchronous methods that return value through a completion handler now have variants that work with async/await:
@IBAction func pickColor(_ sender: Any?) { async { guard let color = await NSColorSampler().sample() else { return } textField.textColor = color } }
The actor model is a great fit for a UI framework like AppKit where most APIs should be called on a single main thread
The macOS SDK now has a @MainActor
property wrapper that marks all types that have to be accessed from the main thread
Classes such as NSView
, NSView/WindowController
, NSApplication
, NSCell
, NSDocument
etc. are now marked with @MainActor
Code running in the main actor can freely call methods on other main actor types
However, code that isn’t running on the main thread needs to use async/await to run code on a @MainActor
type
This is enforced at the compiler level, which lets you avoid common errors that happen when mixing concurrency with UI code
See “Meet async/await in Swift” and “Protect mutable state with Swift actors” for more info
AttributedString:
Swift 5.5 also adds a new value type AttributedString
It has type-safe attributes and a more swifty API for reading & writing attributes
You can easily convert between AttributedString
and NSAttributedString
See “What’s new in Foundation” for more info
Updating NSViews:
There is a new Swift property wrapper which should reduce boilerplate around view properties
Let’s say we have a custom view class like this:
class BadgeView: NSView { var fillColor: NSColor var shadow: NSShadow var scaling: NSImageScaling … }
These properties will usually need to have a didSet
which updates properties like needsDisplay
or needsLayout
when they’re modified:
var fillColor: NSColor { didSet { needsDisplay = true } }
The new @Invalidating
attribute in NSView
lets you easily specify which other view properties should be updated when the given property is modified:
@Invalidating(.display) var fillColor: NSColor
Properties that can be invalidated include: display, layout, constraints, intrinsic content size, restorable state
The marked property needs to be Equatable
, since AppKit checks if the value was actually changed before triggering a view update
You can extend the invalidation system by conforming to NSViewInvalidating
protocol
Shortcuts
iOS Shortcuts are now available on the Mac
Shortcuts appear in all the places where you can access services today – if your app supports services, it will also support Shortcuts
AppKit decides which shortcuts are available at the given place by checking the responder chain
It asks each responder whether it can provide or receive the type of data used by each shortcut
The types of data are represented by NSPasteboard.PasteboardType
(usually a UTI)
To support shortcuts in a given responder object, implement the method:
func validRequestor(forSendType sendType: NSPasteboard.PasteboardType?, returnType: NSPasteboard.PasteboardType?) -> Any
In that method return an instance of a type implementing NSServicesMenuRequestor
(usually the same object):
protocol NSServicesMenuRequestor { func writeSelection(to pasteboard: NSPasteboard, types: [NSPasteboard.PasteboardType]) -> Bool func readSelection(from pasteboard: NSPasteboard) -> Bool }
Siri Intents
You can now use Siri Intents in a Mac app by adding an Intents Extension
You can also return an intents handler from the application delegate:
protocol NSApplicationDelegate { optional func application(_ application: NSApplication, handlerFor intent: INIntent) -> Any? }
The returned object should conform to an appropriate intent handler protocol, depending on the intent type
1 comment:
CloClo98
Want to make better food choices as a student? Look no further! Head over to http://www.healthcarebusinesstoday.com/the-students-guide-to-nutrition/ and read further for food ideas tailored to college life.