【问题标题】:Iterate a grid of views SwiftUI迭代视图网格 SwiftUI
【发布时间】:2019-06-22 00:37:14
【问题描述】:

我想获取一个可变长度的数组并返回一个具有 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 网格。

我不知何故需要使用两个索引来迭代行和列,但不知道如何快速做到这一点。

【问题讨论】:

    标签: swift swiftui


    【解决方案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])
                        }
                    }
                }
            }
        }
    }
    

    【讨论】:

    • 这适用于文本网格。谢谢你的垫脚石!使用 CardPicView(cardTitle: self.cards[row*3 + column]) 的小修改效果很好。再次感谢!
    • 我发现这会引发错误:“编译器无法在合理的时间内对该表达式进行类型检查;尝试将表达式分解为不同的子表达式”不知道该怎么做。跨度>
    • @dot3 很可能,“行 * 3 + 列”操作耗时过长。您可能想尝试在视图构建器函数中创建 Text() 视图,该函数在循环中返回 Text()。例如func makeView(row: Int, column: Int) -> Text { let row * 3 + column return Text(self.cards[row * 3 + column]) }
    【解决方案2】:

    这是我使用 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)
            }
        }
    }
    

    结果如下:

    【讨论】:

    • 该代码中发生了很多事情,不过很好地使用了泛型。
    【解决方案3】:

    签出基于 ZStack 的示例 here

    您可以选择固定列样式。

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

    【讨论】:

      猜你喜欢
      • 2020-09-08
      • 1970-01-01
      • 2019-12-28
      • 2011-06-04
      • 2020-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多