如何在SwiftUI中循环viewbuilder内容子视图

如何在SwiftUI中循环viewbuilder内容子视图,swiftui,custom-view,viewbuilder,Swiftui,Custom View,Viewbuilder,因此,我尝试创建一个视图,它接受viewBuilder内容,在内容的视图上循环,并在每个视图和其他视图之间添加分隔符 struct BoxWithDividerView<Content: View>: View { let content: () -> Content init(@ViewBuilder content: @escaping () -> Content) { self.content = content }

因此,我尝试创建一个视图,它接受viewBuilder内容,在内容的视图上循环,并在每个视图和其他视图之间添加分隔符

struct BoxWithDividerView<Content: View>: View {
    let content: () -> Content
    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content
    }
    var body: some View {
        VStack(alignment: .center, spacing: 0) {
            // here
            
        }
        .background(Color.black)
        .cornerRadius(14)
    }
}

如何做到这一点?

所以我最终做了这个

@_functionBuilder
struct UIViewFunctionBuilder {
    static func buildBlock<V: View>(_ view: V) -> some View {
        return view
    }
    static func buildBlock<A: View, B: View>(
        _ viewA: A,
        _ viewB: B
    ) -> some View {
        return TupleView((viewA, Divider(), viewB))
}
}
@\u functionBuilder
结构UIViewFunctionBuilder{
静态func构建块(view:V)->一些视图{
返回视图
}
静态func构建块(
_A:A,
_视图B:B
)->一些观点{
返回TupleView((viewA,Divider(),viewB))
}
}
然后我像这样使用我的函数生成器

struct BoxWithDividerView<Content: View>: View {
    let content: () -> Content
    init(@UIViewFunctionBuilder content: @escaping () -> Content) {
        self.content = content
    }
    var body: some View {
        VStack(spacing: 0.0) {
            content()
        }
        .background(Color(UIColor.AdUp.carbonGrey))
        .cornerRadius(14)
    }
}
struct-BoxWithDividerView:View{
让内容:()->内容
init(@UIViewFunctionBuilder内容:@escaping()->content){
self.content=内容
}
var body:一些观点{
VStack(间距:0.0){
内容()
}
.背景(颜色(UIColor.AdUp.carbonGrey))
.转弯半径(14)
}
}

但问题是,这只适用于最多2个表达式视图。我将发布一个单独的问题,关于如何将数组传递给它,我刚刚回答了另一个类似的问题。链接答案将对此进行任何改进,因此请首先检查

然而,这里的答案是相同的
TupleView
扩展名,但不同的视图代码

用法:

struct ContentView: View {
    
    var body: some View {
        BoxWithDividerView {
            Text("Something 1")
            Text("Something 2")
            Text("Something 3")
            Image(systemName: "circle")  // Different view types work!
        }
    }
}
您的带有分隔视图的

struct BoxWithDividerView: View {
    let content: [AnyView]
    
    init<Views>(@ViewBuilder content: @escaping () -> TupleView<Views>) {
        self.content = content().getViews
    }
    var body: some View {
        VStack(alignment: .center, spacing: 0) {
            ForEach(content.indices) { index in
                if index != 0 {
                    Divider()
                }
                
                content[index]
            }
        }
//        .background(Color.black)
        .cornerRadius(14)
    }
}
结果:


我敢肯定,使用
ViewBuilder
无法做到这一点-它只提供一个由基础视图组合而成的单一视图。如果要保持相同的DSL语法,需要实现自己的
@\u functionBuilder
,类似于
ViewBuilder
,您知道如何实现吗?我正在尝试使用@u functionBuilder:@u functionBuilder struct UIViewFunctionBuilder{static func buildBlock(u-views:[V])->一些视图{return ForEach(views){View in View Divider()}}},但是V应该符合可识别性。有些视图是在线的。我没有亲自做过,所以我帮不了你。如果您有一个关于实现
@\u functionBuilder
的更具体的问题,您可以问另一个问题,我正试图完成完全相同的任务。你有没有提出过一个更健壮的解决方案,可以处理任意数量的视图?@ab1470没有:(如果有需要,请告诉我)do@ab1470请参见下文。@Eddy也会打电话给你:)
struct BoxWithDividerView: View {
    let content: [AnyView]
    
    init<Views>(@ViewBuilder content: @escaping () -> TupleView<Views>) {
        self.content = content().getViews
    }
    var body: some View {
        VStack(alignment: .center, spacing: 0) {
            ForEach(content.indices) { index in
                if index != 0 {
                    Divider()
                }
                
                content[index]
            }
        }
//        .background(Color.black)
        .cornerRadius(14)
    }
}
extension TupleView {
    var getViews: [AnyView] {
        makeArray(from: value)
    }
    
    private struct GenericView {
        let body: Any
        
        var anyView: AnyView? {
            AnyView(_fromValue: body)
        }
    }
    
    private func makeArray<Tuple>(from tuple: Tuple) -> [AnyView] {
        func convert(child: Mirror.Child) -> AnyView? {
            withUnsafeBytes(of: child.value) { ptr -> AnyView? in
                let binded = ptr.bindMemory(to: GenericView.self)
                return binded.first?.anyView
            }
        }
        
        let tupleMirror = Mirror(reflecting: tuple)
        return tupleMirror.children.compactMap(convert)
    }
}