首页 > 解决方案 > SwiftUI LazyVGrid 动态行高

问题描述

我想要一个具有相同高度的 LazyVGrid 行扩展/收缩以填充可用的父高度

可能吗?

let columns = Array(repeating: GridItem(.flexible(minimum: 50, maximum: 100)), count: 3)
LazyVGrid(columns: columns, alignment: .leading, spacing: 10) {
  ForEach(objects, id: \.self.id) { object in
    MyView().frame(minHeight: 0, maxHeight: .infinity)
  }
}

上面的代码确实在宽度上完美地分隔了框架,但行不会扩大和缩小,它们只会紧贴内容的高度。

预期的

标签: iosswiftswiftuilazyvgrid

解决方案


这是一个采用所有可用高度的网格示例。可以用更通用的方式来做,但我希望如何做的想法很清楚。

struct ContentView: View {
    let numOfItems = 10
    let numOfColumns = 3
    let spacing: CGFloat = 10
    
    var body: some View {
        GeometryReader { g in
            let columns = Array(repeating: GridItem(.flexible(minimum: 50, maximum: 100)), count: numOfColumns)
            let numOfRows: Int = Int(ceil(Double(numOfItems) / Double(numOfColumns)))
            let height: CGFloat = (g.size.height - (spacing * CGFloat(numOfRows - 1))) / CGFloat(numOfRows)

            LazyVGrid(columns: columns, alignment: .leading, spacing: spacing) {
                ForEach(0..<numOfItems, id: \.self) { object in
                    MyView().frame(minHeight: height, maxHeight: .infinity)
                }
            }
        }
    }}

struct MyView: View {
    var body: some View {
        Color(red: Double.random(in: 0...1), green: Double.random(in: 0...1), blue: Double.random(in: 0...1))
    }
}

这是这样一个网格的可重用版本:

struct ContentView: View {
    let colors = [UIColor.red, .black, .blue, .brown, .gray, .green, .cyan, .magenta, .orange, .purple]
    var body: some View {
        TallVGrid(items: colors, idKeyPath: \.self, numOfColumns: 4, vSpacing: 20, content: { color in
            ColorView(uiColor: color)
            Text("Some \(Int.random(in: 0...10))")
        })
    }
}

struct TallVGrid<Item, ItemView, I>: View where ItemView: View, I: Hashable {
    var items: [Item]
    var idKeyPath: KeyPath<Item, I>
    var numOfItems : Int {
        items.count
    }
    var numOfColumns : Int = 3
    var vSpacing: CGFloat = 10
    @ViewBuilder var content: (Item) -> ItemView
    
    var body: some View {
        GeometryReader { g in
            let columns = Array(repeating: GridItem(.flexible(minimum: 50, maximum: 100)), count: numOfColumns)
            let numOfRows: Int = Int(ceil(Double(numOfItems) / Double(numOfColumns)))
            let height: CGFloat = (g.size.height - (vSpacing * CGFloat(numOfRows - 1))) / CGFloat(numOfRows)
            
            LazyVGrid(columns: columns, alignment: .leading, spacing: vSpacing) {
                ForEach(items, id: idKeyPath) { item in
                    VStack {
                        content(item)
                    }
                    .frame(minHeight: height, maxHeight: .infinity)
                }
            }
        }
    }
}


struct ColorView: View {
    let uiColor: UIColor
    var body: some View {
        Color(uiColor)
    }
}

推荐阅读