Xcode 11 - SwiftUI 预览深色模式

Xcode 11 - SwiftUI Preview Dark Mode

在 Xcode 11 中,当应用程序 运行 时,我们可以通过像这样在调试区域底部切换环境覆盖来启用暗模式。

SwiftUI 具有 Canvas 编辑器,可在您构建界面时生成应用程序的实时预览。

有没有办法在这些预览中切换到深色模式?

您应该在正在预览的文件底部有这样的内容。这是 Xcode 用于生成预览的内容:

#if DEBUG
struct ContentView_Previews : PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
#endif

要将预览更改为深色模式,您只需指定 colorScheme:

static var previews: some View {
    ContentView().colorScheme(.dark)
}

或者,您甚至可以选择同时预览明暗模式:

static var previews: some View {
    Group {
        ContentView().colorScheme(.light)
        ContentView().colorScheme(.dark)
    }
}

我建议观看 Introducing SwiftUI session 以了解更多 SwiftUI 示例以及预览的强大功能。

Note: At the time of writing, you need a NavigationView as your top-level view for .environment(.colorScheme, .dark) to work. But then the (large) navigation bar covers the color blocks, so the two navigationBar modifiers make the bar smaller and hide it ... sort of. This might be a bug in Xcode.

Source - paid content

我在 Xcode 11.2.1 上对此进行了测试,NavigationView 的问题仍然存在。除非您的整个视图都包含在 NavigationView 中,否则环境似乎不会改变。您可以尝试使用 .navigationBarTitle("").navigationBarHidden(true) 隐藏 NavigationView

示例:

struct ContentView: View {
    var body: some View {
        NavigationView {
            Text("Light vs Dark Mode")

            // Uncomment these lines if you don't want the navigation bar
            // .navigationBarTitle("")
            // .navigationBarHidden(true)

            // You can also apply a colorScheme here
            // which will impact how the view looks when the app
            // is launched on device. Regardless of the users theme settings
        }// .environment(\.colorScheme, .dark)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        // ContentView().environment(\.colorScheme, .dark)
        // ContentView().environment(\.colorScheme, .light)

        // If you want you can display both schemes in a group
        Group {
            ContentView()
            .environment(\.colorScheme, .light)

           ContentView()
           .environment(\.colorScheme, .dark)
       }
    }
}

深色模式下的示例预览:

TLDR:

只需在预览中添加 .background(Color(UIColor.systemBackground)).environment(\.colorScheme, .dark) 修饰符。有关解释、示例、一些修改和一些使它更漂亮甚至更简单的提示,请阅读整个答案。

说明

我知道这个问题已经很老了,但我找到了一种实施起来不太痛苦并且不需要在 NavigationView 中进行任何包装的方法。此外,它还保留了 .previewLayout(.sizeThatFits) 的正确行为。

本质上,当你定义一个符合PreviewProvider的结构时,你只是在定义内容,但预览的背景是由Xcode为你管理的。因此,应用 .environment(\.colorScheme, .dark) 只会将实际 View 更改为暗模式,但不会更改背景。 NavigationView 解决这个问题的原因很简单——它为视图添加了一个背景,覆盖了预览的所有白色背景。

修复本身也相当简单 - 您需要做的就是在预览中为您的视图添加背景。所以对于这样一个简单的视图:

struct ExampleView: View {
    var body: some View {
        Text("Hello, World!")
    }
}

还有一组这样的预览:

struct ExampleView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            ExampleView()
            ExampleView()
                .environment(\.colorScheme, .dark)
        }.previewLayout(.sizeThatFits)
    }
}

您得到如下所示的输出:

为了使第二个预览出现在深色背景上,通过在视图上调用 .background(Color(UIColor.systemBackground)) 添加它:

struct ExampleView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            ExampleView()
            ExampleView()
                .background(Color(UIColor.systemBackground))
                .environment(\.colorScheme, .dark)
        }.previewLayout(.sizeThatFits)
    }
}

您会得到两个如下所示的预览:

额外选项

您可以进行多项修改。首先,根据单元格所在的图层,您可以将 UIColor.systemBackground 替换为 UIColor.secondarySystemBackgroundUIColor.tertiarySystemBackground。阅读有关动态系统颜色的更多信息 in the human interface guidelines or the UI Element Colors portion of the UIColor developer documentation

最后,如果您要经常使用它并且不想每次都写出对 UIColor 的整个调用,那么在 [= 上创建一个扩展可能是个好主意25=] 并将它们定义为静态变量:

extension Color {
    static let systemBackground = Color(UIColor.systemBackground)
    static let secondarySystemBackground = Color(UIColor.secondarySystemBackground)
    static let tertiarySystemBackground = Color(UIColor.tertiarySystemBackground)
}

然后您可以用更好的 Color.systemBackground 替换对 Color(UIColor.systemBackground) 的调用。