I have one requirement where I need to show multiple progress lines can be n number of lines.
current line should be in gradient colour where previous lines should be in green and next lines should be in grey.
I am expecting a view similar to the image added and everything should be done from storyboard I don't want to take any outlets on my view controller class.
Hi You can use the below mentioned code for achieving the result :
@IBDesignable
class PageProgressView: UIView {
@IBInspectable var statusLines: Int = 1 {
didSet {
setupStatusLines()
}
}
@IBInspectable var currentLineIndex: Int = 0 {
didSet {
setupStatusLines()
}
}
@IBInspectable var previousColor: UIColor = UIColor(red: 0.44, green: 0.81, blue: 0.59, alpha: 1) {
didSet {
setupStatusLines()
}
}
@IBInspectable var nextColor: UIColor = UIColor(red: 0.22, green: 0.22, blue: 0.31, alpha: 1) {
didSet {
setupStatusLines()
}
}
@IBInspectable var gradientStart: UIColor = UIColor(resource: .secondary) {
didSet {
setupStatusLines()
}
}
@IBInspectable var gradientEnd: UIColor = UIColor(resource: .primary) {
didSet {
setupStatusLines()
}
}
private let statusLineHeight: CGFloat = 2
private let statusLinePadding: CGFloat = 10.0
private let lineSpacing: CGFloat = 6.0
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setupView()
}
private func setupView() {
backgroundColor = UIColor.white // Set background color
// Add any additional setup for the view here
}
private func setupStatusLines() {
// Remove any existing status lines
subviews.forEach { $0.removeFromSuperview() }
let numberOfLines = CGFloat(statusLines)
let totalSpacing = lineSpacing * (numberOfLines - 1)
let availableWidth = bounds.width - (2 * statusLinePadding) - totalSpacing
let lineWidth = availableWidth / numberOfLines
var currentX: CGFloat = statusLinePadding
// Add status lines
for index in 1...statusLines {
let label = UILabel()
label.text = ""
label.font = UIFont.systemFont(ofSize: 16.0)
label.numberOfLines = 1
label.textAlignment = .center
label.frame = CGRect(x: currentX, y: 0, width: lineWidth, height: statusLineHeight)
label.layer.cornerRadius = statusLineHeight / 2
label.clipsToBounds = true
// Apply background colors
if index < currentLineIndex {
label.backgroundColor = previousColor // Green for previous line
} else if index > currentLineIndex {
label.backgroundColor = nextColor// Grey for next line
} else {
label.backgroundColor = gradientColor() // Apply gradient color to the current line
}
addSubview(label)
currentX += lineWidth + lineSpacing
}
}
private func gradientColor() -> UIColor {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = bounds
gradientLayer.colors = [gradientStart.cgColor, gradientEnd.cgColor] // Customize your gradient colors here
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 0.4, y: 0)
UIGraphicsBeginImageContextWithOptions(gradientLayer.bounds.size, gradientLayer.isOpaque, 0.0)
gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return UIColor(patternImage: image!)
}
}