## DEV Community

Caleb Hearth

Posted on • Originally published at calebhearth.com on

# Custom Hexagon Shape in SwiftUI

Creating custom shapes in SwiftUI is pretty easy. At a high level, to satisfy the Shape protocol you just need to define `path(in rect: CGRect) -> Path`. Shape itself conforms to View, so you can even get a preview in XCode of your shape while you build it.

We’ll call this shape Hexagon, but really we’re building a regular hexagon, meaning that all sides and angles are coequal. You may be tempted to try to build a hexagon of six equilateral triangles, but it’s actually simpler with a bit of trigonometry. Each corner can be calculated by taking the center point + radius × cosine(π × index of the point) for the x coordinate and center point + radius × sine(π × index of the point) for the y coordinate.

Since we’re given a bounding rectangle, we find the center of that rectangle to be the center of the hexagon:

``````let center = CGPoint(x: rect.midX, y: rect.midY)

``````

The radius is the smaller of the height or width, divided by two:

``````let radius = min(rect.size.height, rect.size.width) / 2

``````

We can use those to calculate the corners, returning an array of `CGPoint` for each vertex of the hexagon:

``````func corners(center: CGPoint, radius: CGFloat) -> [CGPoint] {
var points: [CGPoint] = []
for i in (0...5) {
let angle = CGFloat.pi / 3 * i
let point = CGPoint(
x: center.x + radius * cos(angle),
y: center.y + radius * sin(angle)
)
points.append(point)
}
return points
}

``````

Finally, to actually build the Path that’s required from the `path` function, we’ll create a path (`var path = Path()`), move to the first vertex: `path.move(to: corners[0]`, and then iterate over the points, calling `path.addLine(to: point)` for each one. Finally, we can call `path.closeSubpath()` to complete the outline and return the path.

Pulling everything together:

``````struct Hexagon: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
let center = CGPoint(x: rect.midX, y: rect.midY)
let radius = min(rect.size.height, rect.size.width) / 2
path.move(to: corners[0])
corners[1...5].forEach() { point in
}
path.closeSubpath()
return path
}

func corners(center: CGPoint, radius: CGFloat) -> [CGPoint] {
var points: [CGPoint] = []
for i in (0...5) {
let angle = CGFloat.pi / 3 * CGFloat(i)
let point = CGPoint(
x: center.x + radius * cos(angle),
y: center.y + radius * sin(angle)
)
points.append(point)
}
return points
}
}

``````

Shapes can be used in SwiftUI either directly, being added as a View right into another view, to clip an image (say, if you wanted to prove that you spent too much money and electricity on a URL to an image), and can be colored, resized, etc.