Apple 使用以下结构来设置
PresentationBackgroundInteraction
:
public struct PresentationBackgroundInteraction : Sendable {
public static var automatic: PresentationBackgroundInteraction { get }
public static func enabled(upThrough detent: PresentationDetent) -> PresentationBackgroundInteraction
...
}
然后可以在视图修改器中使用它,如下所示;
.presentationBackgroundInteraction(.enabled(upThrough(.medium))
如果我尝试重新创建 Apple 的设置,我会遇到一些问题。让函数返回本身当然会创建无限递归;
public static func enabled(upThrough detent: PresentationDetent) -> PresentationBackgroundInteraction {
.enabled(upThrough: detent)
}
将其分配给内部变量当然可以缓解这个问题。
但是,如果我将它用作视图修饰符,它总是返回结构的实例,而不是我分配的值。所以我永远不能根据传递给我的视图修饰符的值进行更改。
结构
public struct PresentationBackgroundInteractionRecreate : Sendable {
public static var automatic: PresentationBackgroundInteractionRecreate = .automatic
}
查看
EmptyView()
.presentationBackgroundInteractionRecreate(.automatic)
视图修改器
extension View {
public func presentationBackgroundInteractionRecreate(
_ interaction: presentationBackgroundInteractionRecreate
) -> some View {
// This now always returns; PresentationBackgroundInteractionRecreate()
// How would I be able to access `automatic` here
print(interaction)
return EmptyView()
}
}
基于使用
Mirror
和 dump
进行一些基本的逆向工程,我发现 PresentationBackgroundInteraction
基本上是一个枚举的包装器,如下所示:
public struct PresentationBackgroundInteractionRecreate: Hashable, Sendable {
internal enum Kind: Hashable {
case automatic
case disabled
case enabled(upThrough: PresentationDetent?)
}
internal let kind: Kind
internal init(kind: Kind) {
self.kind = kind
}
public static let automatic = Self.init(kind: .automatic)
public static let enabled = Self.init(kind: .enabled(upThrough: nil))
public static let disabled = Self.init(kind: .disabled)
public func enabled(upThrough detent: PresentationDetent) -> Self {
.init(kind: .enabled(upThrough: detent))
}
}
据我所知,
internal
部分甚至可能是fileprivate
。
视图修改器可以轻松读取
kind
。反映 presentationBackgroundInteraction
返回的视图,它似乎使用 transformPreference
,所以我想象视图修改器看起来像这样:
extension View {
func presentationBackgroundInteractionRecreate(_ interaction: PresentationBackgroundInteractionRecreate) -> some View {
transformPreference(PresentationOptionsPreferenceKey.self) { value in
switch interaction.kind {
// change "value" in different ways
}
}
}
}
PresentationOptionsPreferenceKey
是另一种 internal
/fileprivate
类型。我不知道首选项键的 Value
类型是什么,但要点是正确的。
我可以想到使用结构体而不是枚举的一些优点。使用枚举会比结构公开更多的实现细节。 枚举会立即给出它有多少种不同的情况,并且每种情况都是不同的,而对于结构体,
.automatic
不妨在幕后返回
.disabled
,这将是“公平的游戏”。使用结构还可以防止人们对不同情况进行详尽的switch
处理。这使得将来添加更多类型的后台交互变得更加容易。另一方面,枚举强烈向开发人员表明这是一组
固定的值。