Apply FocusedValue for Active macOS Scenes Only in SwiftUI
FocusedValue, focusedSceneValue and commands can be used to improve user experiences like printing.
You have just created the world's best Lyric writing app for macOS.
You get your first feature request; printing. Easy enough because you've heard you can add commands
to your Scene
:
struct ExampleApp: App {
var body: some Scene {
DocumentGroup(newDocument: AppDocument()) { file in
ContentView(document: file.$document)
}
.commands {
CommandGroup(replacing: .printItem) {
Button("Print...") {
// ...
}
.keyboardShortcut("p", modifiers: [.command])
}
}
}
}
You even throw in a cheeky shortcut because you care about making the lives of your users easier.
But wait a second, how does the app know which document to print given a user can have multiple documents opened at the same time.
Please welcome focusedSceneValue(...)
to the stage 👏
Let's get started:
- Create a Focused Value
extension FocusedValues {
enum PrintValueKey: FocusedValueKey {
typealias Value = () -> Void
}
var print: PrintValueKey.Value? {
get { self[PrintValueKey.self] }
set { self[PrintValueKey.self] = newValue }
}
}
- Add the Focused Value to your App
struct ExampleApp: App {
@FocusedValue(\.print) // <--- New
private var print
var body: some Scene {
DocumentGroup(newDocument: AppDocument()) { file in
ContentView(document: file.$document)
}
.commands {
CommandGroup(replacing: .printItem) {
Button("Print...") {
print?() // <--- New
}
.keyboardShortcut("p", modifiers: [.command])
.disabled(print == nil) // <--- If no Scene is active, print is disabled.
}
}
}
}
- Update your
ContentView
to print the document.
struct ContentView: View {
@Binding
var document: AppDocument
var body: some View {
TextEditor(text: $document.text)
.focusedSceneValue(\.print) {
print(document)
}
}
}
Try it out and you too can offer an incredible printing experience like Lyrcs ❤️