Custom Hexagon Shape in SwiftUI
Tags: programming, swift
Published: 2022-08-31 15:41:07

---
title: Custom Hexagon Shape in SwiftUI
published: true
date: 2022-05-15 00:00:00 UTC
tags: programming,swift
canonical_url: http://calebhearth.com/custom-shapes-in-swiftui
---

 ![XCode simulator of an iPhone 13 Mini in portrait orientation showing a black hexagon filling the width of the screen. The background is white.](http://calebhearth.com/assets/iphone-hexagon-9d5b181ab35d87639bf96b6f1caf3f6ea36779df73f2a868115466ba3d1203af.png "XCode simulator of an iPhone 13 Mini in portrait orientation showing a black hexagon filling the width of the screen. The background is white.")

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.

<section>
  <iframe src="https://www.youtube.com/embed/thOifuHs6eY" frameborder="0" allowfullscreen=""></iframe>
</section>