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

问题描述 投票:0回答:2

我试图了解

_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?
    }
}
swift swiftui conditional-statements implementation viewbuilder
2个回答
0
投票

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

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))
}

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


0
投票

Result builders 由 SE-0289 正式定义。 Selection statements 部分描述了如何转换

if/else
statements。对于你的问题,这句话给出了答案:

请注意,

vMerged
的所有赋值都将一起进行类型检查,这应该允许统一注入结果类型中的任何自由泛型参数。

通常情况下,在Swift中,每条语句的类型检查都是独立于其他语句的,因此

if/else
的两个分支内的语句不会影响彼此的类型检查。但是在结果构建器中的
if/else
语句中,两个分支都将结果分配给相同的(合成的)变量,Swift 使用两个分支一起推断该变量的类型。

这类似于

?:
运算符的两个分支必须具有相同类型的方式。例如,使用您对
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 可以通过查看

T
运算符的两个分支来推断
F
?:
的类型。结果生成器使用
if/else
语句的两个分支执行类似的推理。

© www.soinside.com 2019 - 2024. All rights reserved.