Reputation: 17685
@main
struct TestApp: App {
@State private var price = 0
var body: some Scene {
WindowGroup {
ContentView(price: $price)
.focusedValue(\.price, $price)
}
.commands {
PriceCommands()
}
}
}
struct ContentView: View {
@Binding var price: Int
var body: some View {
IncreasePriceButton(price: $price)
}
}
struct IncreasePriceButton: View {
@Binding var price: Int
var body: some View {
Button("Increase Price") {
price += 1
print("price = \(price)")
}
}
}
struct PriceCommandButton: View {
@FocusedBinding(\.price) var price
var body: some View {
Button("Print Price") {
print("price = \(price)")
}
}
}
struct PriceCommands: Commands {
var body: some Commands {
CommandMenu("Custom") {
PriceCommandButton()
.keyboardShortcut(KeyboardShortcut("C", modifiers: [.command, .shift]))
}
}
}
struct FocusedPriceKey: FocusedValueKey {
typealias Value = Binding<Int>
}
extension FocusedValues {
var price: FocusedPriceKey.Value? {
get { self[FocusedPriceKey.self] }
set { self[FocusedPriceKey.self] = newValue }
}
}
Upvotes: 1
Views: 454
Reputation: 1947
So I took the demo code and added a little bit of debug as shown below.
As far as I can tell, there are two problems.
First that focusedValue
on ContentView
was not being set because the View is not being focused. Which can be seen because the @FocusBinding
in OtherView
doesn't pick up the price
value as expected.
This could be a SwiftUI bug, but it's easy to work around by switching over to the focusedSceneValue
modifier. Anyway, with that in place the price
in ContentView
and OtherView
keeps in step.
The second problem is that even with the first fix/workaround in place, changes in the price
are never causing the Custom
menu to be rebuilt after it's initial rendering.
I think this is a bug with SwiftUI and would recommend submitting a feedback submission to Apple letting them know about it.
The workaround (in this case) with price
being app global state, would be to just pass it through to PriceCommands
as an argument (as is already being done for ContentView
).
Kind regards
import SwiftUI
@main
struct TestApp: App {
@State private var price = 0
var body: some Scene {
WindowGroup {
ContentView(price: $price)
.focusedSceneValue(\.price, $price) // <== Changed
}
.commands {
PriceCommands()
}
}
}
struct OtherView: View {
@FocusedBinding(\.price) var price: Int?
var body: some View {
Text("OtherView price = \(String(describing: price))")
}
}
struct ContentView: View {
@Binding var price: Int
var body: some View {
VStack {
OtherView()
IncreasePriceButton(price: $price)
}
}
}
struct IncreasePriceButton: View {
@Binding var price: Int
var body: some View {
Button("Increase Price") {
price += 1
print("price = \(price)")
}
}
}
struct PriceCommandButton: View {
@FocusedBinding(\.price) var price
var priceText: String {
String(price ?? -1)
}
var body: some View {
print("Buiding commands menu with \(String(describing: price))")
return Button("Print Price \(priceText)") {
print("price = \(String(describing: price))")
}
}
}
struct PriceCommands: Commands {
var body: some Commands {
CommandMenu("Custom") {
PriceCommandButton()
.keyboardShortcut(KeyboardShortcut("C", modifiers: [.command, .shift]))
}
}
}
struct FocusedPriceKey: FocusedValueKey {
typealias Value = Binding<Int>
}
extension FocusedValues {
var price: FocusedPriceKey.Value? {
get { self[FocusedPriceKey.self] }
set { self[FocusedPriceKey.self] = newValue }
}
}
Upvotes: 1