Skip to content

Instantly share code, notes, and snippets.

@loromits
Created September 4, 2019 09:15
Show Gist options
  • Save loromits/63548b39a55a233b56421f185fd2896e to your computer and use it in GitHub Desktop.
Save loromits/63548b39a55a233b56421f185fd2896e to your computer and use it in GitHub Desktop.
Create gradient color interpolation of 2 UIColors
import UIKit
extension Comparable {
func clamping(_ range: ClosedRange<Self>) -> Self {
return Swift.min(range.upperBound, max(range.lowerBound, self))
}
}
extension UIColor {
func components() -> (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
var red, green, blue, alpha: CGFloat
(red, green, blue, alpha) = (0, 0, 0, 0)
getRed(&red, green: &green, blue: &blue, alpha: &alpha)
return (red, green, blue, alpha)
}
}
struct ColorInterpolation {
let values: [UIColor]
init(start: UIColor, end: UIColor, stepsCount: Int) {
guard stepsCount > 2 else {
values = [start, end]
return
}
let startComponents = start.components()
let endComponents = end.components()
values = [start]
+ (1..<(stepsCount - 1)).map { step in
let factor = CGFloat(step) / CGFloat(stepsCount)
return UIColor(red: startComponents.red + (endComponents.red - startComponents.red) * factor,
green: startComponents.green + (endComponents.green - startComponents.green) * factor,
blue: startComponents.blue + (endComponents.blue - startComponents.blue) * factor,
alpha: startComponents.alpha + (endComponents.alpha - startComponents.alpha) * factor)
}
+ [end]
}
subscript(factor: CGFloat) -> UIColor {
let cfactor = factor.clamping(0...1)
let findex = cfactor * CGFloat(values.count) - 0.5
let rindex = Int(findex.rounded(.towardZero)).clamping(0...values.endIndex - 1)
return values[rindex]
}
}
@loromits
Copy link
Author

loromits commented Sep 4, 2019

final class ColorInterpolationView: UIView {
    let interpolation: ColorInterpolation
    
    init(start: UIColor, end: UIColor, stepsCount: Int) {
        interpolation = ColorInterpolation(start: start, end: end, stepsCount: stepsCount)
        super.init(frame: .zero)
        setupUI()
    }
    
    @available(*, unavailable)
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupUI() {
        let views = interpolation.values.map(makeView)
        let stack = UIStackView(arrangedSubviews: views)
        stack.distribution = .fillEqually
        addSubview(stack)
        stack.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([stack.topAnchor.constraint(equalTo: topAnchor),
            stack.bottomAnchor.constraint(equalTo: bottomAnchor),
            stack.leadingAnchor.constraint(equalTo: leadingAnchor),
            stack.trailingAnchor.constraint(equalTo: trailingAnchor)])
    }
    
    private func makeView(ofColor color: UIColor) -> UIView {
        let view = UIView()
        view.backgroundColor = color
        return view
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment