简体   繁体   中英

How can I count @ViewBuilder Views in SwiftUI?

I want to to know how can I count my inPutView in this example of code, the code working like this, it takes some views and gave a background color and counts the count of view, thanks for help.

在此处输入图像描述

struct ContentView: View {
    var body: some View {
        
        ModelView(inputView: {
            Text("Hello, world!").padding()
            Text("Hello, world!").padding()
        })
        
    }
}

struct ModelView<Content: View>: View {
    
    var inPutView: () -> Content
    
    init(@ViewBuilder inputView: @escaping () -> Content) { self.inPutView = inputView }
    
    var body: some View {
        
        VStack {
            inPutView()
        }
        .background(Color.green)
        
        Text("count of inPutViews: 2").padding() // Here: How can I found out the count of inPutView?
        
    }
}

update:

    struct ContentView: View {
    
    var inputViews: [AnyView] = [AnyView(Text("Hello, world!").padding()), AnyView(Text("Hello, world!").padding())]
    
    var body: some View {
        
        ModelView2(inputViews: inputViews)
        
    }
}

    struct ModelView2: View {
    var inputViews: [AnyView]

    var body: some View {
        VStack {
            ForEach(inputViews.indices, id:\.self) { index in
                inputViews[index]
            }
        }
        .background(Color.green)

        Text("count of inPutViews: \(inputViews.count)")
            .padding()
    }
}

It's not possible to detect the count if individual views inside a @ViewBuilder closure. The @ViewBuilder creates one resulting view and your inPutView is treated as a single view.

A possible solution is to pass the [AnyView] array as the input of ModelView . But then AnyView doesn't conform to Hashable nor Identifiable , so you can't use it in a ForEach .

In your case you can create a separate struct conforming to Identifiable :

struct AnyViewItem: Identifiable {
    let id = UUID()
    let view: AnyView
}

and populate ModelView with an array of AnyViewItem :

struct ModelView: View {
    var inputViews: [AnyViewItem]

    var body: some View {
        VStack {
            ForEach(inputViews) {
                $0.view
            }
        }
        .background(Color.green)

        Text("count of inPutViews: \(inputViews.count)")
            .padding()
    }
}

Then, you can use it in your main view like this:

struct ContentView: View {
    var body: some View {
        ModelView(
            inputViews: [
                Text("Hello, world!").padding(),
                Text("Hello, world!").padding(),
            ]
            .map {
                AnyViewItem(view: AnyView($0))
            }
        )
    }
}

Alternatively, as suggested in the comments, in this case you can make inputViews an [AnyView] array and iterate through its indices :

ForEach(inputViews.indices, id: \.self) {
    inputViews[$0]
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM