Chapters

Hide chapters

SwiftUI Cookbook

Live Edition · iOS 16.4 · Swift 5.8.1 · Xcode 14.3.1

Make a Custom Segmented Progress Bar in SwiftUI
Written by Team Kodeco

Do you want to visually represent different stages of a task in your SwiftUI app? A segmented progress bar is a perfect way to showcase this. Let’s see how you can create one using the SwiftUI framework.

The crucial SwiftUI components you will use are GeometryReader and HStack. The GeometryReader allows you to access the size and coordinate space of its parent view, which is essential for calculating how much of the progress bar should be filled. HStack is a horizontal stack in which you will put our progress bar segments.

Here’s how you can create a segmented progress bar:

struct ContentView: View {
  @State private var progressOne: CGFloat = 0
  @State private var progressTwo: CGFloat = 0
  @State private var progressThree: CGFloat = 0

  var body: some View {
    VStack {
      GeometryReader { geometry in
        HStack(spacing: 0) {
          RoundedRectangle(cornerRadius: 10)
            .foregroundColor(Color.green)
            .frame(height: 10)
            .frame(width: progressOne * geometry.size.width / 3)
          RoundedRectangle(cornerRadius: 10)
            .foregroundColor(Color.blue)
            .frame(height: 10)
            .frame(width: progressTwo * geometry.size.width / 3)
          RoundedRectangle(cornerRadius: 10)
            .foregroundColor(Color.purple)
            .frame(height: 10)
            .frame(width: progressThree * geometry.size.width / 3)
        }
        .frame(height: 50)
      }
      Button("Start Task") {
        withAnimation(.easeInOut(duration: 2)) {
          progressOne = 1.0
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
          withAnimation(.easeInOut(duration: 2)) {
            progressTwo = 1.0
          }
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
          withAnimation(.easeInOut(duration: 2)) {
            progressThree = 1.0
          }
        }
      }
      .padding()
      Spacer()
    }
    .padding()
  }
}

Your preview should look like this after you tap Start Task:

Use a GeometryReader to implement a custom segmented progress bar.
Use a GeometryReader to implement a custom segmented progress bar.

In this code, you craft a ContentView that features a single progress bar segmented into three parts. Each segment is embodied by a RoundedRectangle view. The segments are laid out horizontally within an HStack, forming a unified progress bar.

Every segment is set to a consistent height of 10 units and is softened with a corner radius of 10 units. The width of each segment is dependent on its corresponding progress variable, progressOne, progressTwo or progressThree. The width of each segment is determined as a proportion of the total width provided by geometry.size.width, divided by the total number of segments, 3 in this case, to ensure each segment fills its part of the bar as progress ensues.

To visually represent progress within each segment of your custom progress bar, you simply need to update the corresponding progress variables. In this example, this is performed by pressing the Start Task button, which incrementally fills up each segment with a smooth animation, giving you a segmented progress bar that fills over time.

Congratulations! You’ve successfully created a custom segmented progress bar in SwiftUI. Now you can tweak it as per your requirements and enrich your app’s user experience.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.