如何创建仅显示线条网格的自定义视图?

How can I create a custom view that only displays a grid of lines?

我正在制作一个测试应用程序,看看使用 Swift 是什么感觉UI,我希望我的测试应用程序有一个自定义视图,它是一个垂直线网格,间距指定为状态变量。

但是,我不知道如何在似乎没有自定义绘图方法的 UI 系统中执行此操作。

import SwiftUI



struct GridBackgroundView : View {

    @State var horizontalSpacing: CGFloat = 48
    @State var verticalSpacing: CGFloat = 48
    @State var anchor: Anchor<CGPoint>.Source = .center


    var numberOfHorizontalGridLines: UInt {
        return // Something?
    }

    var numberOfVerticalGridLines: UInt {
        return // Something?
    }


    var body: some View {
        Group {
            ForEach(0 ... numberOfHorizontalGridLines) { _ in
                // Something?
            }
            ForEach(0 ... numberOfVerticalGridLines) { _ in
                // Something?
            }
        }
    }
}

#if DEBUG
struct GridView_Previews : PreviewProvider {
    static var previews: some View {
        GridBackgroundView()
    }
}
#endif

我不知道在 // Something? 区域放什么。 SwiftUI 中没有内置线视图,我这辈子都不知道视图的宽度是多少(可能是因为那不是 Swift[=19] 中 View 的一部分=]?)

您可以通过组合垫片和分隔片来做到这一点

   var body: some View {
           ZStack {
               HStack {
                   Spacer()
                   Rectangle().frame(width: 1)
                   Spacer()
                   Divider()
                   Spacer()
               }
               VStack {
                   Spacer()
                   Divider()
                   Spacer()
                   Divider()
                   Spacer()
               }
           }
       }

您也可以使用 Rectangle() 代替 Divider() 并查看 https://developer.apple.com/tutorials/swiftui/drawing-paths-and-shapes

upd: 如果你需要一个单元格大小固定的网格,你可以使用 GeometryReader 来计算你的行数,并组织你的 ForEach对应

    var cellSize: CGFloat = 48
    var body: some View {
        GeometryReader { geometry in
            ZStack {
                HStack {
                    ForEach(0..<Int(geometry.size.width / self.cellSize)) { _ in
                        Spacer()
                        Divider()
                    }
                    Spacer().frame(width: geometry.size.width.truncatingRemainder(dividingBy: self.cellSize))
                }
                VStack {
                    ForEach(0..<Int(geometry.size.height / self.cellSize)) { _ in
                        Spacer()
                        Divider()
                    }
                    Spacer().frame(width: geometry.size.height.truncatingRemainder(dividingBy: self.cellSize))
                }
            }
        }
    }

您可以使用 SwiftUI 使用 Path (Path Documentation, Tutorial)

进行自定义绘图

要绘制网格,您可以使用如下内容:

struct ContentView : View {
    var horizontalSpacing: CGFloat = 48
    var verticalSpacing: CGFloat = 48

    var body: some View {
        GeometryReader { geometry in
            Path { path in
                let numberOfHorizontalGridLines = Int(geometry.size.height / self.verticalSpacing)
                let numberOfVerticalGridLines = Int(geometry.size.width / self.horizontalSpacing)
                for index in 0...numberOfVerticalGridLines {
                    let vOffset: CGFloat = CGFloat(index) * self.horizontalSpacing
                    path.move(to: CGPoint(x: vOffset, y: 0))
                    path.addLine(to: CGPoint(x: vOffset, y: geometry.size.height))
                }
                for index in 0...numberOfHorizontalGridLines {
                    let hOffset: CGFloat = CGFloat(index) * self.verticalSpacing
                    path.move(to: CGPoint(x: 0, y: hOffset))
                    path.addLine(to: CGPoint(x: geometry.size.width, y: hOffset))
                }
            }
            .stroke()
        }
    }
}

这可以通过 ZStack 实现,它允许您将其中的视图渲染在彼此之上。

     ZStack {
        HStack(spacing: horizontalSpacing) {
            ForEach(0 ..< Int(numberOfVerticalGridLines)) { _ in
                Rectangle().fill(Color.gray).frame(width: 1)
            }
        }
        VStack(spacing: verticalSpacing) {
            ForEach(0 ..< Int(numberOfHorizontalGridLines)) { _ in
                Rectangle().fill(Color.gray).frame(height: 1)
            }
        }
    }

为了使用 SwiftUI 使用路径绘制网格视图 Drawing Paths and Shapes

struct GridView: View {

    let rows: CGFloat
    let cols: CGFloat
    let gridColor: Color

    var body: some View {
    
        GeometryReader { geometry in
        
            let width = geometry.size.width
            let height = geometry.size.height
            let xSpacing = width / cols
            let ySpacing = height / rows
        
            Path { path in
            
                for index in 0...Int(cols) {
                    let vOffset: CGFloat = CGFloat(index) * xSpacing
                    path.move(to: CGPoint(x: vOffset, y: 0))
                    path.addLine(to: CGPoint(x: vOffset, y: height))
                }
                for index in 0...Int(rows) {
                    let hOffset: CGFloat = CGFloat(index) * ySpacing
                    path.move(to: CGPoint(x: 0, y: hOffset))
                    path.addLine(to: CGPoint(x: width, y: hOffset))
                }
            }
            .stroke(gridColor)
        }
    }
}

GridView(rows: 9.0, cols: 9.0, gridColor: .white)