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
let corners = corners(center: center, radius: radius)
path.move(to: corners[0])
corners[1...5].forEach() { point in
path.addLine(to: point)
}
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.

## Top comments (0)