SwiftUI:在Sheet中更改浅色/深色模式不会刷新Sheet UI

5
我希望在表格中有一个系统/亮色/暗色模式选择器,以及其他设置。
选择不同的方案确实会更改ContentView(表格后面)中的UI,但表格本身仍保留旧的方案,必须关闭并重新打开。
我做错了什么?
示例:
import SwiftUI

struct ContentView: View {
    @EnvironmentObject var viewManager: ViewManager
    @State var showSettingsSheet = false
    
    var body: some View {
        NavigationView {
            List {
                Text("Some content 1")
                Text("Some content 2")
            }
            .toolbar {
                ToolbarItem {
                    Button(action: {
                        showSettingsSheet.toggle()
                    }){
                        Image(systemName: "gearshape.fill")
                    }
                    .sheet(isPresented: $showSettingsSheet){SettingsSheet()}
                }
            }
        }
        .preferredColorScheme(viewManager.colorScheme == "Light" ? .light : viewManager.colorScheme == "Dark" ? .dark : nil)
    }
}

struct SettingsSheet: View {
    @Environment (\.presentationMode) var presentationMode
    @EnvironmentObject var viewManager: ViewManager

    var body: some View {
        NavigationView{
            GroupBox {
                Picker("Display Mode", selection: $viewManager.colorScheme) {
                    Text("System").tag("System")
                    Text("Light").tag("Light")
                    Text("Dark").tag("Dark")
                }
                .pickerStyle(.segmented)
            }
            .toolbar {
                ToolbarItem {
                    Button(action: {
                        presentationMode.wrappedValue.dismiss()
                    }){
                        Text("Done")
                    }
                }
            }
        }
    }
}

class ViewManager: ObservableObject {
    @AppStorage("colorScheme") var colorScheme: String = "System"
}
2个回答

4

通过巨大的变通方法,我成功地让它工作了。不过最好向苹果报告这个问题。

在一个 sheet 内获取 colorScheme 更新时出现了问题,但我们可以将这个 colorScheme 环境变量附加到另一个已发布的变量上,然后在 sheet 中使用该变量。

struct ContentView: View {
    
    @Environment(\.colorScheme) private var colorScheme
    @EnvironmentObject var settings: Settings

    var body: some View {
        ContentView()
        .preferredColorScheme(!settings.automaticAppearance ? (settings.lightAppearance ? .light : .dark) : nil)
        .environmentObject(settings)
        .onChange(of: colorScheme) { newColorScheme in
            // update color scheme to settings (from system environment variable)
            settings.systemColorScheme = newColorScheme
        }
    }
}

final class Settings: ObservableObject {
    
    @Environment(\.colorScheme) var colorScheme
    
    @Published var lightAppearance: Bool {
        didSet {
            UserDefaults.standard.set(lightAppearance, forKey: "light_appearance")
        }
    }
    
    @Published var automaticAppearance: Bool {
        didSet {
            UserDefaults.standard.set(automaticAppearance, forKey: "automatic_appearance")
        }
    }
    
    @Published var systemColorScheme: ColorScheme {
        didSet {
            UserDefaults.standard.set(systemColorScheme.hashValue, forKey: "system_color_scheme")
        }
    }
    
    init() {
        self.lightAppearance = UserDefaults.standard.object(forKey: "light_appearance") as? Bool ?? true
        self.automaticAppearance = UserDefaults.standard.object(forKey: "automatic_appearance") as? Bool ?? true
        self.systemColorScheme = UserDefaults.standard.object(forKey: "system_color_scheme") as? ColorScheme ?? .light
    }
    
}

我希望用户能够切换浅色模式,也可以选择“自动”选项,使用系统的颜色方案。在我的设置表中:
struct SettingsView: View {
    
    @Environment(\.colorScheme) var colorScheme
    @EnvironmentObject var settings: Settings
    
    var body: some View {
        
        List {
                
            Section(header: Text(NSLocalizedString("appearance", comment: "Appearance"))) {
                    
                Group {

                    // appearance
                    Toggle("Light mode", isOn: $settings.lightAppearance)
                        .onChange(of: settings.lightAppearance) { lightAppearance in
                            // if light/dark appearance was set, disable automatic appearance
                            settings.automaticAppearance = false
                        }
                        
                    Toggle(isOn: $settings.automaticAppearance) {
                        Text(NSLocalizedString("automatic", comment: "Automatic"))
                    }

                }

            }
      
        }
        .preferredColorScheme(settings.automaticAppearance ? settings.systemColorScheme : (settings.lightAppearance ? .light : .dark))
    }
}

简而言之:在您的表格中使用不同的已发布变量进行监听,因为环境的颜色方案存在错误。

4

由于colorScheme不在您的视图层次结构中,因此您必须手动向表格提供它:

struct ContentView: View {
    @EnvironmentObject var viewManager: ViewManager
    @State var showSettingsSheet = false
    
    var body: some View {
        NavigationView {
            List {
                Text("Some content 1")
                Text("Some content 2")
            }
            .toolbar {
                ToolbarItem {
                    Button(action: {
                        showSettingsSheet.toggle()
                    }){
                        Image(systemName: "gearshape.fill")
                    }
                    .sheet(isPresented: $showSettingsSheet){
                      SettingsSheet()
                       .preferredColorScheme(viewManager.colorScheme == "Light" ? .light : viewManager.colorScheme == "Dark" ? .dark : nil)  // HERE
                    }
                }
            }
        }
        .preferredColorScheme(viewManager.colorScheme == "Light" ? .light : viewManager.colorScheme == "Dark" ? .dark : nil)
    }
}

1
快了!在切换到浅色或深色模式时,它可以正常工作,但是在切换回系统模式时却不行。有什么想法吗? - blueFox
没错。我已经尝试过了,但是在.sheet上它就是不起作用。看起来这是iOS 15的许多问题之一。我甚至尝试手动设置UIApplication.shared.windows.first?.overrideUserInterfaceStyle为".unspecified",但没有任何结果。该问题仅在sheet消失之前发生。我的建议是查看以下链接中的答案(<iOS 14.5解决方案),并将“系统”外观保存在某个地方。https://stackoverflow.com/questions/65798263/swiftui-how-to-let-the-user-set-the-app-appearance-in-real-time-w-options-lig/65828985#65828985 - cluelessCoder
1
你找到了解决方法吗? - cyril

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接