Skip to main content

Apply FocusedValue for Active macOS Scenes Only in SwiftUI

FocusedValue, focusedSceneValue and commands can be used to improve user experiences like printing.

Updated 2 min readMarkdown
Apply FocusedValue for Active macOS Scenes Only in SwiftUI

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:

  1. 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 }
    }
}
  1. 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.
            }
        }
    }
}
  1. 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 ❤️

About the author

No comments yet. Be the first to comment.