[英]SwiftUI: Update parent view on change of UserDefaults in child view
我正在用最小的配色方案制作游戲。 我將 colors 用作計算的static var
存儲在枚舉中,以便我可以在任何視圖中調用它們。 我正在嘗試制作輔助配色方案(色盲)。 我的代碼如下所示:
enum GameColors {
static var exampleColor: Color {
!UserDefaults.standard.bool(forKey: GamePrefs.colorBlindMode) ? Color.green : Color(red: 0 / 255, green: 213 / 255, blue: 255 / 255)
}
}
enum GamePrefs {
static let colorBlindMode: String = "colorBlindMode"
}
我的設置菜單在我的主菜單視圖中被調用,如下所示:
struct MainMenuView: View {
@State var settingsClicked: Bool = false
var body: some View {
VStack {
Button {
settingsClicked.toggle()
} label: {
Text("Settings")
.foregroundColor(GameColors.exampleColor)
}
if settingsClicked {
SettingsView()
}
}
}
}
struct SettingsView: View {
@AppStorage(GamePrefs.colorBlindMode) var colorBlindMode = false
var body: some View {
Toggle(isOn: $colorBlindMode) {
Text("Color Blind Mode: \(colorBlindMode ? "On" : "Off")")
.foregroundColor(GameColors.exampleColor)
}
}
}
當我切換colorBlindMode
時,只有SettingsView
的 colors 被更新,除非我與之交互,否則主菜單的顏色不會改變。 如何讓兩者都更新?
我嘗試將@AppStorage
屬性包裝器綁定到沒有成功。
您可以嘗試這種方法,在MainMenuView
中使用@AppStorage
和.onReceive
,以確保在單擊SettingsView
時在MainMenuView
中更新/接收GameColors.exampleColor
。
struct MainMenuView: View {
@AppStorage(GamePrefs.colorBlindMode) var colorBlindMode = false // <-- here
@State var settingsClicked: Bool = false
var body: some View {
VStack {
Button {
settingsClicked.toggle()
} label: {
Text("Settings").foregroundColor(GameColors.exampleColor)
}
if settingsClicked {
SettingsView()
}
}
.onReceive(Just(colorBlindMode)) { _ in // <-- here
}
}
}
struct SettingsView: View {
@AppStorage(GamePrefs.colorBlindMode) var colorBlindMode = false
var body: some View {
Toggle(isOn: $colorBlindMode) {
Text("Color Blind Mode: \(colorBlindMode ? "On" : "Off")")
.foregroundColor(GameColors.exampleColor) // <-- here for testing
}
.toggleStyle(SwitchToggleStyle(tint: GameColors.exampleColor))
}
}
你的顏色沒有改變的原因是你的MainMenuView
在你按下切換時沒有刷新。 只有您的SettingsView
被刷新。 所以你需要一些東西來通知你的MainMenuView
有些東西已經改變了。
為此,您可以向MainMenuView
添加另一個 AppStorage,並通過創建對此屬性的依賴項來強制刷新視圖。
struct MainMenuView: View {
@State var settingsClicked: Bool = false
// add the same AppStorage as in SettingsView
@AppStorage(GamePrefs.colorBlindMode) var colorBlindMode = false
var body: some View {
VStack {
Button {
settingsClicked.toggle()
} label: {
let _ = print("text")
Text("Settings")
//this will force the view to update
.foregroundColor(colorBlindMode ? GameColors.exampleColor : GameColors.exampleColor)
}
if settingsClicked {
SettingsView()
}
}
}
}
在閱讀了有關導致 SwiftUI 重新加載視圖的原因以及大量測試不同方法的更多信息之后,我相信解決此問題的最簡單方法是引入一個新的@State
變量,您必須在父視圖的某處使用它:
struct MainMenuView: View {
@State var settingsClicked: Bool = false
@State var reloadView: Bool = false // <-- here
var body: some View {
VStack {
Button {
settingsClicked.toggle()
} label: {
Text("Settings")
.foregroundColor(GameColors.exampleColor)
}
if settingsClicked {
SettingsView(reloadParentView: $reloadView)
}
if reloadView {} // <-- here
}
}
}
struct SettingsView: View {
@Binding var reloadParentView: Bool // <-- here
@AppStorage(GamePrefs.colorBlindMode) var colorBlindMode = false
var body: some View {
Toggle(isOn: $colorBlindMode) {
Text("Color Blind Mode: \(colorBlindMode ? "On" : "Off")")
.foregroundColor(GameColors.exampleColor)
}
.onChange(of: colorBlindMode) { _ in
reloadParentView.toggle() // <-- here
}
}
}
將此 state 從父視圖傳遞到子視圖允許子視圖隨意強制重新加載父視圖。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.