首页 > 解决方案 > SwiftUI 选择器中选定选项的值不会更新视图

问题描述

我在 SwiftUI 应用程序中有以下内容。基本上我有一些我想在整个应用程序中使用的设置(设置类)。我有一个设置视图,它显示一个选择器来选择其中一个设置的值。应用程序的其他视图将仅使用设置的当前设置值。以下设置在 ContentView 中我看到了正确的firstLevel设置值的意义上起作用。但问题是,在 SettingsView 中,我认为因为selectedFirstLevel不是@State,所以它的正确值不会显示在我导航以选择even或者odd(奇怪的是,第一次是正确的)的选择器上。此选择正确地传送到 ContentView,但未在 SettingsView 上正确显示。我该如何解决这个问题?

设置.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 }
}

内容视图.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)
        }
    }
}

标签: iosswiftswiftuiobservedobject

解决方案


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

这是简化和工作的变体。使用 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直接在里面使用它。以防万一。


推荐阅读