@FocusedValue reads a value published by whichever view currently has focus, the way
@Environment reads shared values. The classic use is a macOS main-menu command that acts on
the focused editor's content.
Publishing a Focused Value
Define a FocusedValueKey and register it on FocusedValues. The property must be optional:
SwiftUI sets it to nil when no matching view has focus.
struct FocusedNoteValue: FocusedValueKey {
typealias Value = String
}
extension FocusedValues {
var noteValue: FocusedNoteValue.Value? {
get { self[FocusedNoteValue.self] }
set { self[FocusedNoteValue.self] = newValue }
}
}
The focused view publishes with the focusedValue modifier, and any other view observes it.
struct NoteEditor: View {
@State private var note = "text"
var body: some View {
TextEditor(text: $note)
.focusedValue(\.noteValue, note)
}
}
struct NotePreview: View {
@FocusedValue(\.noteValue) var note
var body: some View {
Text(note ?? "Note is not focused")
}
}
Use focusedSceneValue instead when the reader lives in a different scene, such as a menu
command. For an ObservableObject rather than a value, the pair is focusedObject and
@FocusedObject (scene variant focusedSceneObject).
Writing Back With FocusedBinding
@FocusedValue is read-only. To mutate the focused content, publish a Binding as the
focused value and read it with @FocusedBinding.
struct FocusedNoteBinding: FocusedValueKey {
typealias Value = Binding<String>
}
// NoteEditor publishes the binding:
TextEditor(text: $note)
.focusedValue(\.noteBinding, $note)
struct NoteFormatter: View {
@FocusedBinding(\.noteBinding) var note
var body: some View {
VStack {
Text(note ?? "Note is not focused")
Button("Clear note") { note = "" }
}
}
}
Assigning through the wrapper writes straight into the focused editor's state. Everything
here goes nil the moment focus leaves, so always handle the unfocused case.