如何在 SwiftUI 中循环视图构建器内容子视图

Edd*_*ddy 6 custom-view swiftui viewbuilder

所以我试图创建一个视图,它接受 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

所以在我写“here”的地方,如果有意义的话,我想遍历内容的视图。我将编写一个不起作用的代码,但它解释了我想要实现的目标:

ForEach(content.subviews) { view  in
     view
     Divider()
}
Run Code Online (Sandbox Code Playgroud)

怎么做?

Geo*_*e_E 6

我刚刚回答了另一个类似的问题,链接在这里。对此的任何改进都将针对链接的答案进行,因此请先检查那里。

GitHub 链接(但更高级)位于 Swift 包

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!
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

你的BoxWithDividerView

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, id: \.self) { index in
                if index != 0 {
                    Divider()
                }
                
                content[index]
            }
        }
//        .background(Color.black)
        .cornerRadius(14)
    }
}
Run Code Online (Sandbox Code Playgroud)

最后是主要的事情,TupleView扩展:

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

结果:

结果


Edd*_*ddy 2

所以我最终这样做了

\n
@_functionBuilder\nstruct UIViewFunctionBuilder {\n    static func buildBlock<V: View>(_ view: V) -> some View {\n        return view\n    }\n    static func buildBlock<A: View, B: View>(\n        _ viewA: A,\n        _ viewB: B\n    ) -> some View {\n        return TupleView((viewA, Divider(), viewB))\n}\n}\n
Run Code Online (Sandbox Code Playgroud)\n

然后我像这样使用我的函数生成器

\n
struct BoxWithDividerView<Content: View>: View {\n    let content: () -> Content\n    init(@UIViewFunctionBuilder content: @escaping () -> Content) {\n        self.content = content\n    }\n    var body: some View {\n        VStack(spacing: 0.0) {\n            content()\n        }\n        .background(Color(UIColor.AdUp.carbonGrey))\n        .cornerRadius(14)\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

但问题是这只适用于最多 2 个表达式视图。I\xe2\x80\x99m 将发布一个单独的问题,了解如何向其传递数组

\n