SwiftUI 选择器中所选选项的值不会更新视图

Value of Selected Option From a SwiftUI Picker does not Update the View

我在 SwiftUI 应用程序中有以下内容。基本上我有一些我想在整个应用程序中使用的设置(设置 class)。我有一个设置视图,显示了一个选择器 select 其中一个设置的值。而应用程序的其他视图只会使用设置的当前设置值。以下设置的工作原理是在 ContentView 中我看到 firstLevel 设置的正确值。但问题是在 SettingsView 中,我认为因为 selectedFirstLevel 不是 @State,所以它的正确值没有显示在我导航到 select even 或 [=16= 的选择器上] (奇怪的是,第一次是正确的)。此 selection 已正确传送到 ContentView,但未在 SettingsView 上正确显示。我该如何解决这个问题?

Settings.swift

import Foundation

class Settings: ObservableObject {
    static let shared: Settings = Settings()
    @Published var firstLevel: FirstLevel = .even
}

enum FirstLevel: String, CaseIterable, Identifiable {
    case even
    case odd
    var id: String { self.rawValue }
}

ContentView.swift

import SwiftUI

struct ContentView: View {
    @State private var showSettings: Bool = false
    @ObservedObject var settings = Settings.shared
    var body: some View {
        VStack {
            SettingsButton(showSettings: $showSettings, settings: settings)
            Text(settings.firstLevel.id)
                .padding()
        }
        
    }
}

struct SettingsButton: View {
    @Binding var showSettings: Bool
    var settings: Settings
    var firstLevel: Binding<FirstLevel> {
        return Binding<FirstLevel>(
            get: {
                return self.settings.firstLevel
        }) { newFirstLevel in
            self.settings.firstLevel = newFirstLevel
        }
    }
    var body: some View {
        Button(action: { self.showSettings = true }) {
            Image(systemName: "gear").imageScale(.large)
        }
        .sheet(isPresented: $showSettings) {
            SettingsView(selectedFirstLevel: self.firstLevel)
        }
    }
}

SettingsView.swift

import SwiftUI

struct SettingsView: View {

    @Binding var selectedFirstLevel: FirstLevel
    var body: some View {
        NavigationView {
            Form {
                Picker("First Level", selection: $selectedFirstLevel) {
                    ForEach(FirstLevel.allCases) { level in
                        Text(level.rawValue).tag(level)
                    }
                }
            }
            .navigationBarTitle("Settings", displayMode: .inline)
        }
    }
}

它看起来过于复杂,而且绑定作为不同视图层次结构之间的通信是不可靠的(在你的情况下是 sheet)。

这里是经过简化和有效的变体。测试 Xcode 12 / iOS 14.

struct ContentView: View {
    @ObservedObject var settings = FLevelSettings.shared
    var body: some View {
        VStack {
            SettingsButton(settings: settings)
            Text(settings.firstLevel.id)
                .padding()
        }

    }
}

struct SettingsButton: View {
    @State private var showSettings: Bool = false
    var settings: FLevelSettings
    var body: some View {
        Button(action: { self.showSettings = true }) {
            Image(systemName: "gear").imageScale(.large)
        }
        .sheet(isPresented: $showSettings) {
            FLevelSettingsView(settings: self.settings)
        }
    }
}
struct FLevelSettingsView: View {

    @ObservedObject var settings: FLevelSettings
    var body: some View {
        NavigationView {
            Form {
                Picker("First Level", selection: $settings.firstLevel) {
                    ForEach(FirstLevel.allCases) { level in
                        Text(level.rawValue).tag(level)
                    }
                }
            }
            .navigationBarTitle("Settings", displayMode: .inline)
        }
    }
}

注意:由于 FLevelSettings.shared 的存在,如果你愿意,它可以更加简化,所以你可以直接在 FLevelSettingsView 中使用它。以防万一