SwiftUI 中 ScrollView 中 VStack 元素中的神秘间距或填充

and*_*ewz 12 swiftui

我不明白为什么我有一个元素之间多余的垂直间距ForEach是里面VStack是内ScrollView使用时GeometryReader呈现一个自定义的水平分隔线。

        ScrollView {
            ForEach(self.model1.elements, id: \.self) { element in
                VStack.init(alignment: .leading, spacing: 0) {
                    //                    Text("test") // image 3: works correctly
                    //                        .background(Color.blue)
                    GeometryReader { geometry in
                        Path { path in
                            path.move(to: .init(x: 0, y: 0))
                            path.addLine(to: .init(x: geometry.size.width, y: 0))
                        }
                        .strokedPath(.init(lineWidth: 1, dash: [1,2]))
                    }
//                    .frame(maxHeight: 1) // image 2: uncommenting this line doesn't fix the spacing
                    .foregroundColor(.red)
                    .background(Color.blue)

                    HStack {
                        Text("\(element.index+1)")
                            .font(.system(.caption, design: .rounded))
                            .frame(width: 32, alignment: .trailing)
                        Text(element.element)
                            .font(.system(.caption, design: .monospaced))
                            .frame(maxWidth:nil)
                        Spacer()
                    }
                    .frame(maxWidth:nil)
                    .background(Color.green)
                }
                .border(Color.red)
            }
        }

Run Code Online (Sandbox Code Playgroud)

上面的代码产生这个: 在此处输入图片说明

随着.frame(maxHeight: 1)蓝色填充走了,但仍然有连续之间的空白HStack秒。
在此处输入图片说明

我希望垂直间距像这张图片一样,即 0。这张图片是通过取消注释Text("test")GeometryReader代码和注释代码来实现的。 在此处输入图片说明

我正在使用 Xcode 11.3.1 (11C504)

Rob*_*ier 19

如果我理解你的最终目标,那就是让每一行都用虚线包围,它们之间没有填充,就像这样:

由红色虚线分隔的行

在这种情况下,IMO 您应该将线条放在背景中。例如:

ScrollView {
    VStack(alignment: .leading) {
        ForEach(self.elements, id: \.self) { element in
            HStack {
                Text("\(element.index+1)")
                    .font(.system(.caption, design: .rounded))
                    .frame(width: 32, alignment: .trailing)
                Text(element.element)
                    .font(.system(.caption, design: .monospaced))
                Spacer()
            }
            .background(
                ZStack(alignment: .top) {
                    Color.green
                    GeometryReader { geometry in
                        Path { path in
                            path.move(to: .zero)
                            path.addLine(to: CGPoint(x: geometry.size.width, y: 0))
                        }
                        .strokedPath(StrokeStyle(lineWidth: 1, dash: [1,2]))
                        .foregroundColor(Color.red)
                    }
                }
            )
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

一个关键点是 ScrollView 不是垂直堆叠的容器。它只是获取其内容并使其可滚动。它在你的代码中的内容是一个 ForEach,它生成视图;它并不真的打算将它们列出来。因此,当您将 ScrollView 与 ForEach 结合使用时,没有什么真正负责按照您想要的方式放置视图。要垂直堆叠视图,您需要一个 VStack。

您也可以将其应用于您的结构,但添加另一个 VStack,并获得相同的结果:

ScrollView {
    VStack(spacing: 0) { // <---
        ForEach(self.elements, id: \.self) { element in
            VStack(alignment: .leading, spacing: 0) {
                GeometryReader { geometry in
                    Path { path in
                        path.move(to: .init(x: 0, y: 0))
                        path.addLine(to: .init(x: geometry.size.width, y: 0))
                    }
                    .strokedPath(.init(lineWidth: 1, dash: [1,2]))
                }
                .foregroundColor(.red)
                .frame(height: 1)

                HStack {
                    Text("\(element.index+1)")
                        .font(.system(.caption, design: .rounded))
                        .frame(width: 32, alignment: .trailing)
                    Text(element.element)
                        .font(.system(.caption, design: .monospaced))
                        .frame(maxWidth:nil)
                    Spacer()
                }
            }
            .background(Color.green) // <-- Moved
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 简单地添加“(spacing: 0)”就解决了一个小时徒劳的调试。这是一个救星 (10认同)

小智 13

间距由 生成VStack

创建 时,添加间距VStack参数并将其设置为0

VStack(spacing: 0) {
  Element1()
  Element2()
  Element3()
  Element4()
} 
Run Code Online (Sandbox Code Playgroud)

虚拟堆栈

相同的间距属性可用于HStackLazyVStackLazyHStack