本文介绍了有什么方法可以在SwiftUI中使用@ViewBuilder创建/提取View数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个简单的 struct ,该结构接受一个View数组并返回一个普通的 VStack ,其中包含这些View,但所有View都是对角堆叠的.

I'm trying to create a simple struct that accepts an array of Views and returns an ordinary VStack containing those Views except they all are stacked diagonally.

代码:

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

现在这很好用,但是每当我不得不称呼它时,我总是很生气:

Now this works great but I always get annoyed whenever I have to call it:

LeaningTower(views: [Text("Something 1"), Text("Something 2"), Text("Something 3")])

在这样的数组中列出视图对我来说似乎很奇怪,所以我想知道是否有一种方法可以使用 @ViewBuilder 来调用我的 LeaningTower 结构这个:

Listing the views in an array like that seems extremely odd to me so I was wondering if there was a way I could use @ViewBuilder to call my LeaningTower struct like this:

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 来创建/提取视图数组的方法,请告诉我.

If there's a way to use @ViewBuilder to create/extract an array of Views please let me know.

(即使无法使用 @ViewBuilder 从字面上看,也可以使其看起来更整洁的任何东西都会有很大帮助)

(Even if it isn't possible using @ViewBuilder literally anything that will make it look neater will help out a lot)

推荐答案

与此同时尝试自己找出类似的东西.因此,为了后代和其他人为解决类似问题而昂首阔步.

Came across this while trying to figure out something similar myself. So for the benefit of posterity and others banging their heads against similar problems.

我发现获得子偏移量的最佳方法是使用Swift的键入机制,如下所示.例如

The best way I've found to get child offsets is by using Swift's typing mechanism as follows. e.g.

struct LeaningTowerAnyView: View {
    let inputViews: [AnyView]

    init<V0: View, V1: View>(
        @ViewBuilder content: @escaping () -> TupleView<(V0, V1)>
    ) {
        let cv = content().value
        inputViews = [AnyView(cv.0), AnyView(cv.1)]
    }

    init<V0: View, V1: View, V2: View>(
        @ViewBuilder content: @escaping () -> TupleView<(V0, V1, V2)>) {
        let cv = content().value
        inputViews = [AnyView(cv.0), AnyView(cv.1), AnyView(cv.2)]
    }

    init<V0: View, V1: View, V2: View, V3: View>(
        @ViewBuilder content: @escaping () -> TupleView<(V0, V1, V2, V3)>) {
        let cv = content().value
        inputViews = [AnyView(cv.0), AnyView(cv.1), AnyView(cv.2), AnyView(cv.3)]
    }

    var body: some View {
        VStack {
            ForEach(0 ..< inputViews.count) { index in
                self.inputViews[index]
                    .offset(x: CGFloat(index * 30))
            }
        }
    }
}

用法是

struct ContentView: View {
    var body: some View {
        LeaningTowerAnyView {
            Text("Something 1")
            Text("Something 2")
            Text("Something 3")
        }
    }
}

它还可以与任何视图一起使用,而不仅限于文本,例如

It'll also work with any View and not just Text, e.g.

struct ContentView: View {
    var body: some View {
        LeaningTowerAnyView {
            Capsule().frame(width: 50, height: 20)
            Text("Something 2").border(Color.green)
            Text("Something 3").blur(radius: 1.5)
        }
    }
}

缺点是每个附加View都需要自定义初始化程序,但这听起来像是 Apple用于其堆栈的相同方法

The downside is that each additional View needs a custom initialiser, but it sounds like it's the same approach that Apple is using for their stacks

我怀疑是基于 Mirror 的某些东西,并说服Swift动态调用可变数量的不同名称的方法可能会起作用.但这变得令人恐惧,我大约一个星期前就没时间了;-).如果有人更优雅,那将非常有兴趣.

I suspect something based on Mirror and persuading Swift to dynamically call a variable number of differently named methods might be made to work. But that gets scary and I ran out of time about a week ago ;-) . Would be very interested if anyone's got anything more elegant.

这篇关于有什么方法可以在SwiftUI中使用@ViewBuilder创建/提取View数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 18:04