我正在尝试创建一个通用视图修饰符,我可以使用它进行快速原型开发。
struct If : ViewModifier {
var test: Bool
var then: (_: Content) -> Content
@ViewBuilder func body(content: Content) -> some View {
if test {
then(content)
} else {
content
}
}
}对视图中的元素应用它的正确咒语是什么?
struct ExampleView: View {
var isActive: Bool
HStack {}.modifier(If(test: isActive, then: ??? ))
}我的目标是能够在HStack和其他项目(例如.frame())上有条件地链接函数调用。
发布于 2022-09-01 19:49:54
要将它写成符合ViewModifier的类型是很困难的--也许是不可能的。您可以为then提供这种类型
var then: (_: Content) -> Content但是,您通常希望then返回与给定类型不同的类型,因为修饰符通常就是这样工作的。例如,Text("hello")有Text类型,但是Text("hello").background(Color.red)有ModifiedContent<Text, _BackgroundStyleModifier<Color>>类型。
我们可以尝试将修饰符设置为then返回的类型的泛型。
struct If<Then: View>: ViewModifier {
var test: Bool
@ViewBuilder
var then: (_: Content) -> Then
@ViewBuilder
func body(content: Content) -> some View {
if test {
then(content)
} else {
content
}
}
}但是,当我们尝试使用修饰符时,我们遇到了一个问题:
struct ExampleView: View {
var isActive: Bool
var body: some View {
HStack {
}.modifier(If(test: isActive, then: { $0.background(.red) }))
// ^ Generic parameter 'Then' could not be inferred
}
}为什么不能推断出这种类型呢?类型为ModifiedContent<Content, _BackgroundStyleModifier<Color>>。但是Content实际上是_ViewModifier_Content<If>…的类型别名。除了我们在Then上使Then通用,所以Content是_ViewModifier_Content<If<ModifiedContent<Content, _BackgroundStyleModifier<Color>>>>的类型别名。噢,我们刚把Content放回去了。Content类型别名和Then类型是相互递归的,Swift不能处理无限嵌套的泛型类型。
但是,可以通过使用修饰符方法扩展View来实现类似的效果。通过搜索“迅捷条件修饰符”,你可以找到很多有例子的网页。通常如下所示:
extension View {
@ViewBuilder
func `if`<Content: View>(
_ condition: Bool,
@ViewBuilder transform: (Self) -> Content
) -> some View {
if (condition) {
transform(self)
} else {
self
}
}
}你就这样用它:
struct ExampleView: View {
var isActive: Bool
var body: some View {
HStack {
}.if(isActive) { $0.background(.red) }
}
}但是,请注意,像这样的修饰符可能会导致动画和转换行为不当。问题是,SwiftUI通常认为transform(self)和self具有不同的标识,因为它们位于if语句的不同分支中。这会影响SwiftUI动画的方式。这可能是问题,也可能不是问题,但这就是为什么苹果公司的一般建议是直接使用“惰性”形式的修饰符,而不是引入if-style修饰符。也就是说,对于上面的例子,苹果会推荐这样做:
struct ExampleView: View {
var isActive: Bool
var body: some View {
HStack {
}.background(isActive ? .red : .clear)
}
}在这里,没有if语句,因此为了动画的目的,SwiftUI将在对isActive的更改中识别HStack是相同的。
https://stackoverflow.com/questions/73574299
复制相似问题