首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Swift通用ViewModifier

Swift通用ViewModifier
EN

Stack Overflow用户
提问于 2022-09-01 19:02:30
回答 1查看 54关注 0票数 0

我正在尝试创建一个通用视图修饰符,我可以使用它进行快速原型开发。

代码语言:javascript
复制
struct If : ViewModifier {
    var test: Bool
    var then: (_: Content) -> Content
    @ViewBuilder func body(content: Content) -> some View {
        if test {
            then(content)
        } else {
            content
        }
    }
}

对视图中的元素应用它的正确咒语是什么?

代码语言:javascript
复制
struct ExampleView: View {
    var isActive: Bool
    HStack {}.modifier(If(test: isActive, then: ??? ))
}

我的目标是能够在HStack和其他项目(例如.frame())上有条件地链接函数调用。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-09-01 19:49:54

要将它写成符合ViewModifier的类型是很困难的--也许是不可能的。您可以为then提供这种类型

代码语言:javascript
复制
var then: (_: Content) -> Content

但是,您通常希望then返回与给定类型不同的类型,因为修饰符通常就是这样工作的。例如,Text("hello")Text类型,但是Text("hello").background(Color.red)ModifiedContent<Text, _BackgroundStyleModifier<Color>>类型。

我们可以尝试将修饰符设置为then返回的类型的泛型。

代码语言:javascript
复制
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
        }
    }
}

但是,当我们尝试使用修饰符时,我们遇到了一个问题:

代码语言:javascript
复制
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来实现类似的效果。通过搜索“迅捷条件修饰符”,你可以找到很多有例子的网页。通常如下所示:

代码语言:javascript
复制
extension View {
    @ViewBuilder
    func `if`<Content: View>(
        _ condition: Bool,
        @ViewBuilder transform: (Self) -> Content
    ) -> some View {
        if (condition) {
            transform(self)
        } else {
            self
        }
    }
}

你就这样用它:

代码语言:javascript
复制
struct ExampleView: View {
    var isActive: Bool
    var body: some View {
        HStack {
        }.if(isActive) { $0.background(.red) }
    }
}

但是,请注意,像这样的修饰符可能会导致动画和转换行为不当。问题是,SwiftUI通常认为transform(self)self具有不同的标识,因为它们位于if语句的不同分支中。这会影响SwiftUI动画的方式。这可能是问题,也可能不是问题,但这就是为什么苹果公司的一般建议是直接使用“惰性”形式的修饰符,而不是引入if-style修饰符。也就是说,对于上面的例子,苹果会推荐这样做:

代码语言:javascript
复制
struct ExampleView: View {
    var isActive: Bool
    var body: some View {
        HStack {
        }.background(isActive ? .red : .clear)
    }
}

在这里,没有if语句,因此为了动画的目的,SwiftUI将在对isActive的更改中识别HStack是相同的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73574299

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档