Segmented Progress Bar on iOS with UIKit

Step-by-step guide on implementing a segmented progress bar on iOS with UIKit

Ruslan Dzhafarov
4 min readMay 28, 2024
Design by Salman Rahman (Behance)

Introduction

In this tutorial, we will walk you through the step-by-step process of creating a segmented progress bar using UIKit. This segmented bar can be used to display progress or indicate steps in a process, enhancing the user experience in your iOS applications.

Step 1: Create a New UIView Subclass

First, create a new UIView subclass named SegmentBarView. This will be the main component for our segmented progress bar.

import UIKit

final class SegmentBarView: UIView {

}

Step 2: Define the Model

Define a Model struct inside the SegmentBarView to hold the configuration for the segmented bar. This struct will include an array of colors and a spacing value.

import UIKit

final class SegmentBarView: UIView {

// MARK: - Model

struct Model {
let colors: [UIColor]
let spacing: CGFloat
}

private var model: Model?
}

Step 3: Add a Method to Set the Model

Create a method to set the model and update the view’s subviews based on the model’s colors.

import UIKit

final class SegmentBarView: UIView {

// MARK: - Model

struct Model {
let colors: [UIColor]
let spacing: CGFloat
}

private var model: Model?

func setModel(_ model: Model) {
self.model = model

subviews.forEach { $0.removeFromSuperview() }

let views = model.colors.map {
let view = UIView()
view.backgroundColor = $0
view.cornerRadius = 3
return view
}

views.forEach { addSubview($0) }

setNeedsLayout()
}
}

Step 3: Calculate Segment Width

Let’s create a helper function to calculate the width of each segment based on the available width, total segments, and spacing between them.


import UIKit

final class SegmentBarView: UIView {

// MARK: - Model

struct Model {
let colors: [UIColor]
let spacing: CGFloat
}

private var model: Model?

func setModel(_ model: Model) {
self.model = model

subviews.forEach { $0.removeFromSuperview() }

let views = model.colors.map {
let view = UIView()
view.backgroundColor = $0
view.cornerRadius = 3
return view
}

views.forEach { addSubview($0) }

setNeedsLayout()
}

// MARK: - Helpers

static func calculateSegmentWidth(total: Int, spacing: CGFloat, width: CGFloat) -> CGFloat {
guard total > 0 else { return 0 }

let totalSpacing = CGFloat(total - 1) * spacing
let availableWidth = width - totalSpacing
let segmentWidth = availableWidth / CGFloat(total)

return CGFloat.maximum(0, segmentWidth)
}
}

Step 4: Implement Layout Logic

Override the layoutSubviews method to position the segments within the view. Calculate the width of each segment and set the frames of the subviews accordingly.

import UIKit

final class SegmentBarView: UIView {

// MARK: - Model

struct Model {
public let colors: [UIColor]
public let spacing: CGFloat
}

private var model: Model?

func setModel(_ model: Model) {
self.model = model

subviews.forEach { $0.removeFromSuperview() }

let views = model.colors.map {
let view = UIView()
view.backgroundColor = $0
view.cornerRadius = 3
return view
}

views.forEach { addSubview($0) }

setNeedsLayout()
}

// MARK: - Layout

override func layoutSubviews() {
super.layoutSubviews()

guard let model,
!model.colors.isEmpty else { return }

let segmentWidth = Self.calculateSegmentWidth(
total: model.colors.count,
spacing: model.spacing,
width: bounds.width
)

var offset: CGFloat = 0

for subview in subviews {
subview.frame = .init(
x: offset,
y: 0,
width: segmentWidth,
height: 6
)

offset += segmentWidth + model.spacing
}
}

// MARK: - Helpers

static func calculateSegmentWidth(total: Int, spacing: CGFloat, width: CGFloat) -> CGFloat {
guard total > 0 else { return 0 }

let totalSpacing = CGFloat(total - 1) * spacing
let availableWidth = width - totalSpacing
let segmentWidth = availableWidth / CGFloat(total)

return CGFloat.maximum(0, segmentWidth)
}
}

Step 6: Using the SegmentBarView

To use the SegmentBarView, create an instance of the view and set its model with a few colors and spacing.

let segmentBarView = SegmentBarView()

let colors = [
UIColor.blue,
UIColor.blue,
UIColor.blue,
UIColor.lightGray,
UIColor.lightGray
]

let model = SegmentBarView.Model(colors: colors, spacing: 8)

segmentBarView.setModel(model)

Add segmentBarView to your view controller's view and set its frame or constraints as needed.

view.addSubview(segmentBarView)

Conclusion

By following these steps, you’ve created a customizable segmented progress bar in UIKit. This segmented bar can be used to display progress or steps, providing a visual enhancement to your iOS applications. Feel free to extend and customize this component further to suit your app’s needs.

Thank you for reading until the end. If you have any questions, please feel free to write them in the comments.

If you enjoyed reading this article, please press the clap button 👏 . Your support encourages me to share more of my experiences and write more articles like this. Follow me here on medium for more updates!

Happy coding! 😊👨‍💻👩‍💻

More from Ruslan Dzhafarov

Advanced UIKit Techniques

9 stories

Design Patterns in Swift

9 stories

Advanced Swift Programming

3 stories

--

--

Ruslan Dzhafarov
Ruslan Dzhafarov

Written by Ruslan Dzhafarov

Senior iOS Developer since 2013. Sharing expert insights, best practices, and practical solutions for common development challenges

No responses yet