Search code examples
iosswift

Coloured progress lines - Swift


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.

Image for reference

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.


Solution

  • 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!)
        }
    }
    

    You can set colours and other properties from storyboard check here here