在SwiftUI应用中实现暗模式切换

时间:2019-10-20 18:31:22

标签: ios swift swiftui ios-darkmode

我目前正在我的应用程序中进入暗模式。虽然由于我的SwiftUI基础,暗模式本身并没有太大的麻烦,但我仍在努力选择独立于系统ColorScheme来设置ColorScheme的选项。

I found this in apples human interface guidelines,我想实现此功能。 (链接:Human Interface Guidelines

有人知道如何在SwiftUI中做到这一点吗?我发现了一些有关@Environment的提示,但没有有关此主题的更多信息。 (链接:Last paragraph

3 个答案:

答案 0 :(得分:3)

使用@AppStorage切换暗模式的演示

PS:对于全局切换,应将修饰符添加到WindowGroup / MainContentView

import SwiftUI

struct SystemColor: Hashable {
    var text: String
    var color: Color
}

let backgroundColors: [SystemColor] = [.init(text: "Red", color: .systemRed), .init(text: "Orange", color: .systemOrange), .init(text: "Yellow", color: .systemYellow), .init(text: "Green", color: .systemGreen), .init(text: "Teal", color: .systemTeal), .init(text: "Blue", color: .systemBlue), .init(text: "Indigo", color: .systemIndigo), .init(text: "Purple", color: .systemPurple), .init(text: "Pink", color: .systemPink), .init(text: "Gray", color: .systemGray), .init(text: "Gray2", color: .systemGray2), .init(text: "Gray3", color: .systemGray3), .init(text: "Gray4", color: .systemGray4), .init(text: "Gray5", color: .systemGray5), .init(text: "Gray6", color: .systemGray6)]

struct DarkModeColorView: View {

    @AppStorage("isDarkMode") var isDarkMode: Bool = true

    var body: some View {
        Form {
            Section(header: Text("Common Colors")) {
                ForEach(backgroundColors, id: \.self) {
                    ColorRow(color: $0)
                }
            }
        }
        .toolbar {
            ToolbarItem(placement: .principal) { // navigation bar
               Picker("Color", selection: $isDarkMode) {
                    Text("Light").tag(false)
                    Text("Dark").tag(true)
                }
                .pickerStyle(SegmentedPickerStyle())
            }
        }
        .modifier(DarkModeViewModifier())
    }
}

private struct ColorRow: View {

    let color: SystemColor

    var body: some View {
        HStack {
            Text(color.text)
            Spacer()
            Rectangle()
                .foregroundColor(color.color)
                .frame(width: 30, height: 30)
        }
    }
}

public struct DarkModeViewModifier: ViewModifier {

    @AppStorage("isDarkMode") var isDarkMode: Bool = true

    public func body(content: Content) -> some View {
        content
            .environment(\.colorScheme, isDarkMode ? .dark : .light)
            .preferredColorScheme(isDarkMode ? .dark : .light) // tint on status bar
    }
}

struct DarkModeColorView_Previews: PreviewProvider {
    static var previews: some View {
        NavigationView {
            DarkModeColorView()
        }
    }
}

enter image description here

答案 1 :(得分:3)

@Mojtaba Hosseini's 的回答确实帮助了我,但我使用的是 iOS14 的 @main 而不是 SceneDelegate,以及一些 UIKit 视图,所以我最终使用了类似的东西这(这不会切换模式,但它会在 SwiftUIUIKit 之间设置暗模式:

@main
struct MyTestApp: App {

    @Environment(\.scenePhase) private var phase

    var body: some Scene {
        WindowGroup {
            ContentView()
                .accentColor(.red)
                .preferredColorScheme(.dark)
        }
        .onChange(of: phase) { _ in
            setupColorScheme()
        }
    }

    private func setupColorScheme() {
        // We do this via the window so we can access UIKit components too.
        let window = UIApplication.shared.windows.first
        window?.overrideUserInterfaceStyle = .dark
        window?.tintColor = UIColor(Color.red)
    }
}

答案 2 :(得分:0)

首先,您需要访问窗口以更改在UserInterfaceStyle中调用UIKit的应用colorScheme。

我在SceneDelegate中使用了它:

private(set) static var shared: SceneDelegate?

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    Self.shared = self
    ,,,
}

然后,您需要将操作绑定到切换。因此,您需要一个模型。

struct ToggleModel {
    var isDark: Bool = true {
        didSet { SceneDelegate.shared?.window!.overrideUserInterfaceStyle = isDark ? .dark : .light }
    }
}

最后,您只需要切换开关即可

struct ContentView: View {
     @State var model = ToggleModel()

     var body: some View {
         Toggle(isOn: $model.isDark) {
             Text("is Dark")
        }
    }
}