跳到主要内容

在 SwiftUI 中同时预览深色和浅色模式视图

· 阅读需 3 分钟
GoSwiftUI
goswiftui.com

iOS 的深色和浅色模式功能在首次引入时受到广泛欢迎。如今,高质量应用几乎默认需要同时支持两种配色方案。本文不深入实现细节,而是介绍如何通过一个简单的 SwiftUI 视图结构,轻松同时预览两种模式。

iOS 框架对深色/浅色模式有很好的支持,但预览阶段往往需要手动切换。下面介绍一种更高效的方式。

强制指定配色方案

旧的(已废弃)方式是使用视图修饰符:

@inlinable public func colorScheme(_ colorScheme: ColorScheme) -> some View

这个修饰符有个关键问题:它会改变整个屏幕的配色方案,而非仅作用于所应用的视图。视图层级中多个视图同时使用时可能引发不确定行为。

因此改用新的修饰符:

@inlinable public func preferredColorScheme(_ colorScheme: ColorScheme?) -> some View

创建可复用的预览组件

利用 SwiftUI 的视图构建器(@ViewBuilder)功能,创建一个可在整个应用中复用的预览组件。ColorScheme 枚举实现了 CaseIterable 协议,可以方便地遍历所有配色方案:

struct ColorSchemesPreview<Content: View>: View {
let content: Content

init(@ViewBuilder content: () -> Content) {
self.content = content()
}

var body: some View {
ForEach(ColorScheme.allCases, id: \.self) { colorScheme in
content.preferredColorScheme(colorScheme)
}
}
}

设置一个简单的预览来演示该组件:

struct ColorSchemesPreview_Previews: PreviewProvider {
static var previews: some View {
ColorSchemesPreview {
Text("Hello")
Text("world!")
}
.padding()
.previewLayout(.sizeThatFits)
}
}

注意 padding()previewLayout(.sizeThatFits) 直接作用于 ColorSchemesPreview 类型。这得益于视图构建器机制,使我们能像使用系统提供的 SwiftUI 组件一样指定视图。

更进一步:使用视图修饰符

可以通过视图修饰符进一步扩展:

struct ColorSchemesViewModifier: ViewModifier {
func body(content: Content) -> some View {
Group {
ForEach(ColorScheme.allCases, id: \.self) { colorScheme in
content.preferredColorScheme(colorScheme)
}
}
}
}

View 上添加扩展,便于调用:

extension View {
func colorSchemesPreview() -> some View {
self.modifier(ColorSchemesViewModifier())
}
}

用视图修饰符简化 ColorSchemesPreview

struct ColorSchemesPreview<Content: View>: View {
let content: Content

init(@ViewBuilder content: () -> Content) {
self.content = content()
}

var body: some View {
content.colorSchemesPreview()
}
}

更新预览代码展示修饰符用法:

struct ColorSchemesPreview_Previews: PreviewProvider {
static var previews: some View {
Group {
Text("Hello")
Text("world!")
}
.padding()
.previewLayout(.sizeThatFits)
.colorSchemesPreview()
}
}

预览愉快!✌️

原文地址:https://peterringset.dev/articles/light-and-dark-preview