1

我正在尝试创建一个可滚动的项目网格。我创建了一个名为的自定义视图GridView,用于GeometryReader将空间划分为 和 中的列和HStacksVStacks。但由于某种原因,它的大小在ScrollView. 在屏幕截图中,您看到GridView(红色)和它的父VStack级(绿色)缩小了。网格内的项目仍然可见,呈现在其区域之外,但无法正确滚动。

为什么GridView不是包含其项目所需的大小?如果是这样,我认为这个 UI 会正确滚动。

在此处输入图像描述

struct ContentView: View {
    var body: some View {
        ScrollView {
            VStack {
                Text("Section 1")
                GridView(columns: 2, items: [1, 3, 5, 7, 9, 11, 13, 15]) { num in
                    Text("Item \(num)")
                }
                .background(Color.red.opacity(0.2))
            }.background(Color.green.opacity(0.2))
        }.background(Color.blue.opacity(0.2))
    }
}

struct GridView<Content>: View where Content: View {
    var columns: Int
    let items: [Int]
    let content: (Int) -> Content

    init(columns: Int, items: [Int], @ViewBuilder content: @escaping (Int) -> Content) {
        self.columns = columns
        self.items = items
        self.content = content
    }
    var rowCount: Int {
        let (q, r) = items.count.quotientAndRemainder(dividingBy: columns)
        return q + (r == 0 ? 0 : 1)
    }
    func elementFor(_ r: Int, _ c: Int) -> Int? {
        let i = r * columns + c
        if i >= items.count { return nil }
        return items[i]
    }
    var body: some View {
        GeometryReader { geo in
            VStack {
                ForEach(0..<self.rowCount) { ri in
                   HStack {
                        ForEach(0..<self.columns) { ci in
                            Group {  
                                if self.elementFor(ri, ci) != nil {
                                    self.content(self.elementFor(ri, ci)!)
                                        .frame(width: geo.size.width / CGFloat(self.columns),
                                               height: geo.size.width / CGFloat(self.columns))
                                } else {
                                    Text("")
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
4

1 回答 1

1

GeometryReader 是一个容器视图,它将其内容定义为其自身大小和坐标空间的函数。将灵活的首选大小返回到其父布局。

struct ContentView: View {
    var body: some View {
        ScrollView {
            VStack {
                Text("Section 1")
                GridView(columns: 2, items: [1, 3, 5, 7, 9, 11, 13, 15]) { num in
                    Text("Item \(num)")
                }
                .background(Color.red.opacity(0.5))
            }.background(Color.green.opacity(0.2))
        }.background(Color.blue.opacity(0.2))
    }
}

GridView 的高度是多少? 嗯...行数乘以网格单元格的高度,即 GridView 的高度除以行数...

方程没有解:-)

是的,我可以看到,您将网格单元格的高度定义为 GridView 的宽度除以列数,但 SwiftUI 并不那么聪明。

您必须计算 GridView 的高度。我将行数固定为 4 以简化它...

struct ContentView: View {
    var body: some View {
        GeometryReader { g in
        ScrollView {
            VStack {
                Text("Section 1")
                GridView(columns: 2, items: [1, 3, 5, 7, 9, 11, 13, 15]) { num in
                    Text("Item \(num)")
                }.frame(height: g.size.width / 2 * CGFloat(4))
                .background(Color.red.opacity(0.5))
            }.background(Color.green.opacity(0.2))
        }.background(Color.blue.opacity(0.2))
        }
    }
}

您最好从 GridView.body 中删除几何阅读器和网格单元格框架,并在内容视图中设置单元格的大小。

struct ContentView: View {
    var body: some View {
        GeometryReader { g in
        ScrollView {
            VStack {
                Text("Section 1")
                GridView(columns: 2, items: [1, 3, 5, 7, 9, 11, 13, 15]) { num in
                    Text("Item \(num)").frame(width: g.size.width / 2, height: g.size .width / 2)
                }
                .background(Color.red.opacity(0.5))
            }.background(Color.green.opacity(0.2))
        }.background(Color.blue.opacity(0.2))
        }
    }
}

如您所见,GridView 的高度无需定义,方程现在有了解。

于 2020-02-27T15:13:57.420 回答