Are there maximum limits to VStack?

前端 未结 2 1602
醉话见心
醉话见心 2021-01-11 09:45

I started with a clean project and added 5 buttons and 5 spacers in a VStack and all is good. When I add the 6th spacer at the bottom, the code suddenly won\'t compile with

相关标签:
2条回答
  • 2021-01-11 10:12

    You can have at most 10 children in your VStack (and ZStack, HStack, and so forth). This is strictly related to their implementation and to the implementation of the @ViewBuilder closures in general. Look at the interfaces here below (you can find them through xCode, I slightly simplified them in order to be more readable):

    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
    }
    

    As you can see you can build those kind of views with at most 10 children. Each buildBlock method takes an exact number of views as parameters. This is because @ViewBuilder closures, at least at the moment, don't support variadic arguments.

    A workaround can be:

    struct ContentView: View {
        var body: some View {
            VStack {
                Group {
                    //10 views here
                }
    
                Group {
                    //10 views here
                }
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-11 10:17

    SwiftUI uses ViewBuilder to construct the views that make up many SwiftUI views, like VStack, HStack, List, etc. If you take a look at the ViewBuilder documentation, you'll see that the buildBlock function has many copies, each with a different amount of views as arguments. The function with the most amount of views only takes in 10 views which is why you are seeing the limitation that you observed. A way to work around this is by using 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")
        }
    }
    

    Although if you want 20 views that are really similar to each other, it is encouraged to use something like a ForEach to avoid making your views too bloated. The above workaround should only be used if the >10 views are truly unique. Even then, a more SwiftUI-y method would be to split up these views into more smaller views:

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

    Of course, in this specific example, you can just have the two ForEachs in the original view, but in more complex cases, the point still stands. For example, in a form with many elements (e.g. in a job application form: first name, last name, address, phone number text fields, education dropdown menus, date fields, etc.) you can still split up one view into smaller components (in the job application example - a personal information view, an educational information view, etc.).

    0 讨论(0)
自定义标题
段落格式
字体
字号
代码语言
提交回复
热议问题