一个结果构建器实现,允许定义形状构建闭包和变量。
在 SwiftUI 中,你可能会遇到想要根据视图样式更改 Shape
属性的情况。想象一下,你构建了一个视图,它应该呈现圆形外观,或者根据给定的圆角半径具有圆角。你可能会写出类似以下的代码:
struct MyFancyView: View {
let isRound: Bool
var body: some View {
// Fancy content here
.mask(maskingLayer)
}
var maskingLayer: some Shape {
if isRound {
return Circle()
} else {
return RoundedRectangle(cornerRadius: 10)
}
}
}
然而,这段代码无法编译,因为 maskingLayer 声明了一个不透明的返回类型,但在其主体中没有返回语句来推断底层类型。换句话说:Swift 期望 maskingLayer 始终是相同的类型。
解决这个问题的一种方法是引入一个类型擦除的 AnyShape 辅助工具,并将返回的 maskingLayer 擦除为 AnyShape。这种方法类似于 SwiftUI 内置的类型擦除 AnyView。
struct AnyShape: Shape {
let _path: (CGRect) -> Path
init<S: Shape>(_ shape: S) {
_path = shape.path(in:)
}
func path(in rect: CGRect) -> Path {
_path(rect)
}
}
struct MyFancyView: View {
let isRound: Bool
var body: some View {
// Fancy content here
.mask(maskingLayer)
}
var maskingLayer: some Shape {
if isRound {
return AnyShape(Circle())
} else {
return AnyShape(RoundedRectangle(cornerRadius: 10))
}
}
}
正如你所看到的,这要求我们将原始形状包裹在 AnyShape 类型擦除包装器中,这并不是你见过的最漂亮的代码,但它确实有效,不是吗?🤷♂️
解决这个问题的第二种方法是定义一个类似于 SwiftUI 自己的 @ViewBuilder
的结果构建器。这个库实现了 @ShapeBuilder
和 @InsettableShapeBuilder
结果构建器,允许你摆脱类型擦除的形状包装器视图,甚至不需要 return 语句。用相应的result builder标记你的计算属性或函数,你就搞定了。
struct MyFancyView: View {
let isRound: Bool
var body: some View {
// Fancy content here
.mask(maskingLayer)
}
@ShapeBuilder var maskingLayer: some Shape {
if isRound {
Circle()
} else {
RoundedRectangle(cornerRadius: 10)
}
}
}
此外,这个库提供了 BuiltShape
和 BuiltInsettableShape
协议,它们与 SwiftUI 的 View
协议具有相似之处。它们定义了一个只读的 shape
计算属性,该属性用 @ShapeBuilder
/@InsettableShapeBuilder
注解标记。
这允许你定义 BuiltShape
,它们本身就是形状,并采用形状属性的形式。
struct MyFancyMask: BuiltShape {
let isCircle: Bool
var shape: some Shape {
if isCircle {
Circle()
} else {
RoundedRectangle(cornerRadius: 10)
}
}
}
如果你想将 ShapeBuilder 添加到你的 Swift 包中,请将其作为依赖项添加到你的 Package.swift
中。
dependencies: [
.package(
url: "https://github.com/ohitsdaniel/ShapeBuilder.git",
from: "0.1.0"
)
],
targets: [
.target(
name: "MyAwesomePackage",
dependencies: [
"ShapeBuilder"
]
)
]
你可以通过 Xcode 将 ShapeBuilder 添加到你的项目中。打开你的项目,点击 File → Swift Packages → Add Package Dependency…,输入仓库 URL (https://github.com/ohitsdaniel/ShapeBuilder.git) 并将包产品添加到你的应用程序目标。
本库在 MIT 许可证下发布。有关详细信息,请参阅 LICENSE。