Implement dark mode switch in SwiftUI App

后端 未结 2 465
天命终不由人
天命终不由人 2020-12-10 18:08

I\'m currently looking into Dark Mode in my App. While Dark Mode itself isn\'t much of a struggle because of my SwiftUI basis i\'m struggling with the option to set the Colo

相关标签:
2条回答
  • 2020-12-10 18:46

    A demo of using @AppStorage to switch dark mode

    PS: For global switch, modifier should be added to 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()
            }
        }
    }
    

    0 讨论(0)
  • 2020-12-10 18:55

    Single View

    To change the color scheme of a single view (Could be the main ContentView of the app), you can use the following modifier:

    .environment(\.colorScheme, .light) // or .dark
    

    or

    .preferredColorScheme(.dark)
    

    Also, you can apply it to the ContentView to make your entire app dark!

    Assuming you didn't change the ContentView name in scene delegate or @main


    Entier App (Including the UIKit parts and The SwiftUI)

    First you need to access the window to change the app colorScheme that called UserInterfaceStyle in UIKit.

    I used this in SceneDelegate:

    private(set) static var shared: SceneDelegate?
    
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        Self.shared = self
        ...
    }
    

    Then you need to bind an action to the toggle. So you need a model for it.

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

    At last, you just need to toggle the switch:

    struct ContentView: View {
         @State var model = ToggleModel()
    
         var body: some View {
             Toggle(isOn: $model.isDark) {
                 Text("is Dark")
            }
        }
    }
    

    From the UIKit part of the app

    Each UIView has access to the window, So you can use it to set the . overrideUserInterfaceStyle value to any scheme you need.

    myView.window?.overrideUserInterfaceStyle = .dark
    
    0 讨论(0)
提交回复
热议问题