[英]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.