Skip to content

Instantly share code, notes, and snippets.

@kylehughes
Last active Jan 2, 2022
Embed
What would you like to do?
A view modifier for SwiftUI that renders a configurable grid on top of the view. It is useful while designing in code.
// Copyright 2022 Kyle Hughes
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
// OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import SwiftUI
public struct Grid {
public static let defaultColor: Color = .black
public static let defaultLineWidth: CGFloat = 1
private let color: Color
private let lineWidth: CGFloat
private let numberOfColumns: Int
private let numberOfRows: Int
// MARK: Public Initialization
public init(
_ numberOfCellsOnEachAxis: Int,
color: Color = defaultColor,
lineWidth: CGFloat = defaultLineWidth
) {
self.init(numberOfCellsOnEachAxis, numberOfCellsOnEachAxis, color: color, lineWidth: lineWidth)
}
public init(
_ numberOfRows: Int,
_ numberOfColumns: Int,
color: Color = defaultColor,
lineWidth: CGFloat = defaultLineWidth
) {
self.numberOfRows = numberOfRows
self.numberOfColumns = numberOfColumns
self.color = color
self.lineWidth = lineWidth
}
}
// MARK: - View Extension
extension Grid: View {
// MARK: View Body
public var body: some View {
GeometryReader { geometry in
Path { path in
let columnWidth = geometry.size.width / CGFloat(numberOfColumns)
let rowHeight = geometry.size.height / CGFloat(numberOfRows)
for column in 0 ... numberOfColumns {
let offset = CGFloat(column) * columnWidth
path.move(to: CGPoint(x: offset, y: 0))
path.addLine(to: CGPoint(x: offset, y: geometry.size.height))
}
for row in 0 ... numberOfRows {
let offset = CGFloat(row) * rowHeight
path.move(to: CGPoint(x: 0, y: offset))
path.addLine(to: CGPoint(x: geometry.size.width, y: offset))
}
}
.stroke(color, lineWidth: lineWidth)
}
}
}
// MARK: - Extension for View
extension View {
// MARK: Public Instance Interace
public func overlayWithGrid(
_ numberOfCellsOnEachAxis: Int,
color: Color = Grid.defaultColor,
lineWidth: CGFloat = Grid.defaultLineWidth
) -> some View {
overlay(Grid(numberOfCellsOnEachAxis, color: color, lineWidth: lineWidth))
}
public func overlayWithGrid(
_ numberOfRows: Int,
_ numberOfColumns: Int,
color: Color = Grid.defaultColor,
lineWidth: CGFloat = Grid.defaultLineWidth
) -> some View {
overlay(Grid(numberOfRows, numberOfColumns, color: color, lineWidth: lineWidth))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment