如何在SwiftUI中创建条件内容?

i7uaboj4  于 2023-04-10  发布在  Swift
关注(0)|答案(2)|浏览(109)

我试图理解_ConditionalContent的内部工作原理,但我无法为它实现一个resultBuilder。这是_ConditionalContent的一些resultBuilder的定义:

static func buildEither<T: View, F: View>(first: T) -> _ConditionalContent<T, F>

这对我来说没有意义,因为F是如何确定的?它不能被类型擦除为AnyView,因为我已经看到两个类型参数都是具体的SwiftUI视图,例如_ConditionalContent<Text, Button>。只有与其他buildEither(second:)函数一起确定_ConditionalContent的最终类型才有意义。
我无法得到一个粗略的版本,所以如果有人可以向我解释如何使用结果构建器实现这个**,请让我知道:

struct ConditionalConent<T: View, F: View> {
    let trueContent: T
    let falseContent: F
}

@resultBuilder
struct ConditionalContentBuilder {
    static func buildBlock<V: View>(_ content: V) -> V {
        return content
    }

    static func buildEither<T: View, F: View>(first: T) -> ConditionalContent<T, F> {
        // ... how is ConditionalContent created?
    }

    static func buildEither<T: View, F: View>(second: F) -> ConditionalContent<T, F> {
        // ... how is ConditionalContent created?
    }
}
v8wbuo2f

v8wbuo2f1#

结果构建器由SE-0289正式定义。Selection语句一节描述了if/else语句是如何转换的。对于你的问题,答案如下:
请注意,对vMerged的所有赋值都将一起进行类型检查,这应该允许注入结果类型中的任何自由泛型参数被统一。
通常,在Swift中,每个语句都是独立于其他语句进行类型检查的,因此if/else的两个分支中的语句不会影响彼此的类型检查。但是在结果构建器中的if/else语句中,两个分支都将结果分配给同一个(合成)变量,Swift使用两个分支一起推断该变量的类型。
这类似于?:运算符的两个分支必须具有相同的类型。例如,使用your definition of ConditionalContent,我们可以这样写:

import SwiftUI

struct ConditionalContent<T: View, F: View> {
    var condition: Condition

    enum Condition {
        case isTrue(T)
        case isFalse(F)
    }
}

let vMerged: ConditionalContent = 1 > 2
    ? .init(condition: .isTrue(Text("really big one")))
    : .init(condition: .isFalse(Text("normal sized one").opacity(0.5)))

print(type(of: vMerged))
// output: ConditionalContent<Text, ModifiedContent<Text, _OpacityEffect>>

Swift可以通过查看?:运算符的两个分支来推断TF的类型。结果构建器使用if/else语句的两个分支执行类似的推断。

wb1gzix0

wb1gzix02#

我设法让它使用枚举工作:

struct ConditionalContent<T: View, F: View> {
    var condition: Condition
    
    enum Condition {
        case isTrue(T)
        case isFalse(F)
    }
}
static func buildEither<T: View, F: View>(first component: T) -> ConditionalContent <T, F> {
    return ConditionalContent(condition: .isTrue(component))
}
    
static func buildEither<T: View, F: View>(second component: F) -> ConditionalContent <T, F> {
    return ConditionalContent(condition: .isFalse(component))
}

如果我有机会进一步研究这个问题,我会回来编辑这个答案,并分享任何新的见解。

相关问题