迭代视图网格SwiftUI

时间:2019-06-22 00:37:14

标签: swift swiftui

我想要一个可变长度的数组,并返回具有3列和可变行长的视图网格。该视图应根据数组值更新其内容。

以下代码将为每张卡显示一个CardPicView,在滚动视图中标题为“ A” ...“ I”。

struct ContentView : View {
    let cards = ["A", "B", "C", "D", "E", "F", "G", "H", "I"]
    var body: some View {
        ScrollView {
            ForEach(cards.identified(by: \.self)) { card in
                    CardPicView(cardTitle: card)
            }
        }
    }
}

我想使用此滚动视图,基本上将其分为3列。

我发现以下代码可以使用以下方法创建正确大小的网格:

struct ContentView : View {
    let cards = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]
    var body: some View {
        ScrollView{
            ForEach(0..<cards.count/3) { row in // create number of rows
                HStack {
                    ForEach(0..<3) { column in // create 3 columns
                        Text(self.cards[row])
                    }
                }
            }
        }
    }
}

但是,这给了我一个只有(AAA / BBB / CCC / DDD)的3x4网格

更改为:

struct ContentView : View {
    let cards = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]
    var body: some View {
        ScrollView{
            ForEach(0..<cards.count/3) { row in // create number of rows
                HStack {
                    ForEach(0..<3) { column in // create 3 columns
                        Text(self.cards[column])
                    }
                }
            }
        }
    }
}

给我一​​个只有(ABC / ABC / ABC / ABC)的3x4网格。

我不知何故需要使用两个索引在行和列上进行迭代,但不确定如何迅速进行。

3 个答案:

答案 0 :(得分:1)

我认为SwiftUI并没有阻止它的特定功能。我认为这就是您要完成的工作?

struct ContentView : View {
    let cards = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]
    var body: some View {
        ScrollView{
            ForEach(0..<cards.count/3) { row in // create number of rows
                HStack {
                    ForEach(0..<3) { column in // create 3 columns
                        Text(self.cards[row * 3 + column])
                    }
                }
            }
        }
    }
}

答案 1 :(得分:0)

这是我使用Swift泛型的方法。

import SwiftUI

struct Grid<Content: View>: View {

    let rows: Int
    let columns: Int
    let content: (Int, Int) -> Content

    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            ForEach(0..<rows) { row in
                Divider()
                HStack(alignment: .center, spacing: 30) {
                    ForEach(0..<self.columns) { (column) in
                        self.content(row, column)
                        .padding()
                    }
                    .background(LinearGradient(gradient: Gradient(colors: [Color.yellow, Color.green]), startPoint: .leading, endPoint: .trailing))
                    .clipShape(Capsule())
                    .shadow(radius: 3)
                }
            }
            Divider()
        }
    }
}

struct CardPicView: View {
    @State var displayText: String
    var body: some View {
        HStack(alignment: .center, spacing: 4) {
            Image(systemName: "\(displayText).circle.fill")
                .foregroundColor(.blue)
            Text(displayText)
                .multilineTextAlignment(.leading)
                .frame(maxWidth: .infinity)
            Spacer(minLength: 0)
        }
        .font(.title) // sets equal hight both for image and text
        .frame(maxWidth: .infinity)

    }
}

struct ContentView: View {
    var cards = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "w", "l", "m", "n", "ww"]
    @Environment(\.horizontalSizeClass) var horizontalSizeClass
    private var numberOfcolumns: Int {
        (horizontalSizeClass == .compact) ? 2 : 4
    }
    // need to ensure number of rows is rounded up to the next whole integer
    private var numberOfrows: Int {
        Int(ceil(Double(cards.count)/Double(numberOfcolumns)))
    }
    var body: some View {
        ScrollView {
            Grid(rows: numberOfrows, columns: numberOfcolumns) { (r, c) in
                CardPicView(displayText: self.cards[guarded: r*self.numberOfcolumns + c] ?? "_")
            }
            .padding()
        }
        .background(Color(red: 1.0, green: 0.6, blue: 0.95))
    }
}

// subscript for safe access
extension Array {
   subscript(guarded idx: Int) -> Element? {
        guard (startIndex..<endIndex).contains(idx) else { return nil }
        return self[idx]
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            ContentView()
            .environment((\.horizontalSizeClass), .compact)
            ContentView()
             .previewDevice(PreviewDevice(stringLiteral: "iPad8,5"))
             .environment((\.horizontalSizeClass), .regular)
        }
    }
}

结果看起来像这样: .compact and .regular layouts in one preview

答案 2 :(得分:-2)

基于ZStack的示例here

您可以选择固定列样式。

Grid(self.cards) { card in
    Card(title: "\(number)")
}
.gridStyle(
    FixedColumnsGridStyle(columns: 3, itemHeight: 160)
)

enter image description here