Search code examples
iosswiftuiprogressbar

UIProgressBar: How to Change UILabel Color according to Background Color


I'm new to iOS programming. I want to create a progress bar with a UIlabel which also change text color according to background color like this: sample image

Please don't mark the question as duplicate. Because the solution I found are in Obj C or some Pods. But I wanted the solution in Swift because I didn't have any knowledge about Obj-C.

Thanks!


Solution

  • If you want an answer in swift, here is the code(changed from objc to swift) from this post, which should be exactly what you need:

    This is swift 4

    class MyProgressView: UIView {
    
        var progress: CGFloat = 0 {
            didSet {
                setNeedsDisplay()
            }
        }
    
        override func draw(_ rect: CGRect) {
            let context = UIGraphicsGetCurrentContext()
    
            // Set up environment.
            let size = bounds.size
            let backgroundColor = UIColor(red: 108/255, green: 200/255, blue: 226/255, alpha: 1)
            let foregroundColor = UIColor.white
            let font = UIFont.boldSystemFont(ofSize: 42)
    
            // Prepare progress as a string.
            let progress = NSString(format: "%d%%", Int(round(self.progress * 100))) // this cannot be a String because there are many subsequent calls to NSString-only methods such as `size` and `draw`
            var attributes: [NSAttributedString.Key: Any] = [.font: font]
            let textSize = progress.size(withAttributes: attributes)
            let progressX = ceil(self.progress * size.width)
            let textPoint = CGPoint(x: ceil((size.width - textSize.width) / 2), y: ceil((size.height - textSize.height) / 2))
    
            // Draw background + foreground text
            backgroundColor.setFill()
            context?.fill(bounds)
            attributes[.foregroundColor] = foregroundColor
            progress.draw(at: textPoint, withAttributes: attributes)
    
            // Clip the drawing that follows to the remaining progress's frame
            context?.saveGState()
            let remainingProgressRect = CGRect(x: progressX, y: 0, width: size.width - progressX, height: size.height)
            context?.addRect(remainingProgressRect)
            context?.clip()
    
            // Draw again with inverted colors
            foregroundColor.setFill()
            context?.fill(bounds)
            attributes[.foregroundColor] = backgroundColor
            progress.draw(at: textPoint, withAttributes: attributes)
    
            context?.restoreGState()
        }
    }
    

    Tested with playground