【问题标题】:Are there maximum limits to VStack?VStack 有最大限制吗?
【发布时间】:2020-02-12 07:53:44
【问题描述】:

我从一个干净的项目开始,在 VStack 中添加了 5 个按钮和 5 个垫片,一切都很好。当我在底部添加第 6 个间隔时,代码突然无法编译并出现错误:“对成员 'buildBlock()' 的模糊引用”。

是什么导致了这个错误?这是与 SwiftUI 相关的错误吗?或者它是一个功能?这不是我第一次注意到 VStack 或 HStack 的条目数量有限,是否有相关文档?

不完全是鼓舞人心的信心,我应该切换回 UIKit 吗?

【问题讨论】:

标签: swiftui vstack


【解决方案1】:

SwiftUI 使用ViewBuilder 构造构成许多 SwiftUI 视图的视图,例如 VStackHStackList 等。如果您查看 ViewBuilder 文档,您会看到buildBlock 函数有许多副本,每个副本都有不同数量的视图作为参数。视图数量最多的功能只接受 10 个视图,这就是为什么您会看到您观察到的限制。解决此问题的一种方法是使用Groups:

VStack {
    Group {
        Text("Placeholder 0")
        Text("Placeholder 1")
        Text("Placeholder 2")
        Text("Placeholder 3")
        Text("Placeholder 4")
        Text("Placeholder 5")
        Text("Placeholder 6")
        Text("Placeholder 7")
        Text("Placeholder 8")
        Text("Placeholder 9")
    }
    Group {
        Text("Other Placeholder 10")
        Text("Other Placeholder 11")
        Text("Other Placeholder 12")
        Text("Other Placeholder 13")
        Text("Other Placeholder 14")
        Text("Other Placeholder 15")
        Text("Other Placeholder 16")
        Text("Other Placeholder 17")
        Text("Other Placeholder 18")
        Text("Other Placeholder 19")
    }
}

虽然如果您想要 20 个彼此非常相似的视图,我们还是鼓励您使用 ForEach 之类的东西,以避免让您的视图过于臃肿。仅当大于 10 个视图确实是唯一的时,才应使用上述解决方法。即便如此,更 SwiftUI-y 的方法是将这些视图拆分为更小的视图:

VStack {
    SingleDigitPlaceholders()
    TeensPlaceholders()
}

struct SingleDigitPlaceholders: View {
    var body: some View {
        ForEach(0..<10) { i in
            Text("Placeholder \(i)")
        }
    }
}
struct TeensPlaceholders: View {
    var body: some View {
        ForEach(10..<20) { i in
            Text("Other Placeholder \(i)")
        }
    }
}

当然,在这个具体的例子中,你可以只拥有原始视图中的两个ForEachs,但在更复杂的情况下,这一点仍然成立。例如,在具有许多元素的表单中(例如,在工作申请表中:名字、姓氏、地址、电话号码文本字段、教育下拉菜单、日期字段等),您仍然可以将一个视图拆分为更小的组件(在工作申请示例中 - 个人信息视图、教育信息视图等)。

【讨论】:

    【解决方案2】:

    您的VStack(以及ZStackHStack 等)中最多可以有10 个孩子。这与它们的实现以及一般@ViewBuilder 闭包的实现密切相关。看看下面的接口(你可以通过xCode找到它们,为了更具可读性,我稍微简化了它们):

    public struct ViewBuilder {    
        /// Builds an empty view from an block containing no statements, `{ }`.
        public static func buildBlock() -> EmptyView
    
        /// Passes a single view written as a child view (e..g, `{ Text("Hello") }`) through
        /// unmodified.
        public static func buildBlock<Content>(_ content: Content) -> Content where Content : View
    }
    
    extension ViewBuilder {    
        public static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)> where C0 : View, C1 : View
    }
    
    extension ViewBuilder {
        public static func buildBlock<C0, C1, C2>(_ c0: C0, _ c1: C1, _ c2: C2) -> TupleView<(C0, C1, C2)> where C0 : View, C1 : View, C2 : View
    }
    
    extension ViewBuilder {
        public static func buildBlock<C0, C1, C2, C3>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3) -> TupleView<(C0, C1, C2, C3)> where C0 : View, C1 : View, C2 : View, C3 : View
    }
    
    extension ViewBuilder {
        public static func buildBlock<C0, C1, C2, C3, C4>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4) -> TupleView<(C0, C1, C2, C3, C4)> where C0 : View, C1 : View, C2 : View, C3 : View, C4 : View
    }
    
    extension ViewBuilder {
        public static func buildBlock<C0, C1, C2, C3, C4, C5>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5) -> TupleView<(C0, C1, C2, C3, C4, C5)> where C0 : View, C1 : View, C2 : View, C3 : View, C4 : View, C5 : View
    }
    
    extension ViewBuilder {
        public static func buildBlock<C0, C1, C2, C3, C4, C5, C6>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6) -> TupleView<(C0, C1, C2, C3, C4, C5, C6)> where C0 : View, C1 : View, C2 : View, C3 : View, C4 : View, C5 : View, C6 : View
    }
    
    extension ViewBuilder {
        public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7)> where C0 : View, C1 : View, C2 : View, C3 : View, C4 : View, C5 : View, C6 : View, C7 : View
    }
    
    extension ViewBuilder {
        public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7, _ c8: C8) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8)> where C0 : View, C1 : View, C2 : View, C3 : View, C4 : View, C5 : View, C6 : View, C7 : View, C8 : View
    }
    
    extension ViewBuilder {
        public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8, C9>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7, _ c8: C8, _ c9: C9) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where C0 : View, C1 : View, C2 : View, C3 : View, C4 : View, C5 : View, C6 : View, C7 : View, C8 : View, C9 : View
    }
    

    如您所见,您最多可以使用 10 个孩子构建此类视图。每个buildBlock 方法都将确切数量的视图作为参数。这是因为@ViewBuilder 闭包,至少目前不支持可变参数。

    解决方法可以是:

    struct ContentView: View {
        var body: some View {
            VStack {
                Group {
                    //10 views here
                }
    
                Group {
                    //10 views here
                }
            }
        }
    }
    

    【讨论】:

    • 我围绕我的观点添加了组,我仍然在调用错误中收到 Extra 参数。
    【解决方案3】:

    在我的视图周围添加组后,我有 6 个视图,我仍然在调用错误中收到 Extra 参数。

    这就是我修复错误的方法。

    struct ContentView: View {
        var body: some View {
            VStack {
                Group {
                    //3 views here
                }
    
                Group {
                    //3 views here
                }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-01-28
      • 1970-01-01
      • 1970-01-01
      • 2018-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多