ios - 有什么方法可以在 SwiftUI 中使用 @ViewBuilder 创建/提取 View 数组

标签 ios arrays swift swiftui viewbuilder

我正在尝试创建一个简单的 struct接受一个 View 数组并返回一个普通的 VStack包含这些 View ,但它们都是对角堆叠的。
代码:

struct LeaningTower<Content: View>: View {
    var views: [Content]
    var body: some View {
        VStack {
            ForEach(0..<views.count) { index in
                self.views[index]
                    .offset(x: CGFloat(index * 30))
            }
        }
    }
}
现在这很好用,但每当我不得不调用它时,我总是很生气:
LeaningTower(views: [Text("Something 1"), Text("Something 2"), Text("Something 3")])
在这样的数组中列出 View 对我来说似乎非常奇怪,所以我想知道是否有一种方法可以使用 @ViewBuilder调用我的LeaningTower像这样的结构:
LeaningTower {  // Same way how you would create a regular VStack
    Text("Something 1")
    Text("Something 2")
    Text("Something 3")
    // And then have all of these Text's in my 'views' array
}
如果有办法使用@ViewBuilder要创建/提取 View 数组,请告诉我。
(即使无法使用 @ViewBuilder 字面上任何使它看起来更整洁的东西都会有很大帮助)

最佳答案

您很少需要从 中提取 View 。数组 .如果您只是想通过 @ViewBuilder将内容放入 View 中,您可以简单地执行以下操作:

struct ContentView: View {
    var body: some View {
        VStackReplica {
            Text("1st")
            Text("2nd")
            Text("3rd")
        }
    }
}

struct VStackReplica<Content: View>: View {
    @ViewBuilder let content: () -> Content

    var body: some View {
        VStack(content: content)
    }
}
如果这对您的用例来说还不够,请参见下文。

我有一个通用版本,所以不需要为不同长度的元组制作多个初始化器。此外, View 可以是任何你想要的(你不会被限制为每个 View 都是相同的类型)。
您可以在 GeorgeElsham/ViewExtractor 找到我为此制作的 Swift 包。 .这包含的不仅仅是这个答案中的内容,因为这个答案只是一个简化的基本版本。由于代码与此答案略有不同,因此请阅读 README.md首先举个例子。
回到答案,示例用法:
struct ContentView: View {
    
    var body: some View {
        LeaningTower {
            Text("Something 1")
            Text("Something 2")
            Text("Something 3")
            Image(systemName: "circle")
        }
    }
}
你的观点的定义:
struct LeaningTower: View {
    private let views: [AnyView]
    
    init<Views>(@ViewBuilder content: @escaping () -> TupleView<Views>) {
        views = content().getViews
    }
    
    var body: some View {
        VStack {
            ForEach(views.indices) { index in
                views[index]
                    .offset(x: CGFloat(index * 30))
            }
        }
    }
}
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)
    }
}
结果:
Result

关于ios - 有什么方法可以在 SwiftUI 中使用 @ViewBuilder 创建/提取 View 数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62730374/

相关文章:

ios - 将图像编辑成圆形并插入 Swift 中的另一个图像

ios - UICollectionView 宽度以编程方式与 Storyboard初始化冲突

python - 如何通过 id 有效地求和和表示 2D NumPy 数组?

android - 在骰子游戏中比较数组

swift - 如何使用 swift 4 在 ios firebase 中存储用户数据

ios - 如何在 React Native 中实现单选按钮

arrays - Laravel Blade : pass array as parameter to yield section

Swift函数只能调用一次

使用嵌套框架的 iOS 问题

ios - 共享到应用程序的共享扩展时未调用 UIDocumentInteractionControllerDelegate 方法