Simple swift color picker popover (iOS) Simple swift color picker popover (iOS) ios ios

Simple swift color picker popover (iOS)


Here's one I made which is as simple as it gets. It's just a lightweight UIView that allows you to specify the element size in case you want blocked regions (elementSize > 1). It draws itself in interface builder so you can set element size and see the consequences. Just set one of your views in interface builder to this class and then set yourself as a delegate. It will tell you when someone either taps or drags on it and the uicolor at that location. It will draw itself to its own bounds and there's no need for anything other than this class, no image required.

Element size=1 (Default)element size=1

Element size=10
element size=10

internal protocol HSBColorPickerDelegate : NSObjectProtocol {    func HSBColorColorPickerTouched(sender:HSBColorPicker, color:UIColor, point:CGPoint, state:UIGestureRecognizerState)}@IBDesignableclass HSBColorPicker : UIView {    weak internal var delegate: HSBColorPickerDelegate?    let saturationExponentTop:Float = 2.0    let saturationExponentBottom:Float = 1.3    @IBInspectable var elementSize: CGFloat = 1.0 {        didSet {            setNeedsDisplay()        }    }    private func initialize() {        self.clipsToBounds = true        let touchGesture = UILongPressGestureRecognizer(target: self, action: #selector(self.touchedColor(gestureRecognizer:)))        touchGesture.minimumPressDuration = 0        touchGesture.allowableMovement = CGFloat.greatestFiniteMagnitude        self.addGestureRecognizer(touchGesture)    }   override init(frame: CGRect) {        super.init(frame: frame)        initialize()    }    required init?(coder aDecoder: NSCoder) {        super.init(coder: aDecoder)        initialize()    }    override func draw(_ rect: CGRect) {        let context = UIGraphicsGetCurrentContext()        for y : CGFloat in stride(from: 0.0 ,to: rect.height, by: elementSize) {            var saturation = y < rect.height / 2.0 ? CGFloat(2 * y) / rect.height : 2.0 * CGFloat(rect.height - y) / rect.height            saturation = CGFloat(powf(Float(saturation), y < rect.height / 2.0 ? saturationExponentTop : saturationExponentBottom))            let brightness = y < rect.height / 2.0 ? CGFloat(1.0) : 2.0 * CGFloat(rect.height - y) / rect.height            for x : CGFloat in stride(from: 0.0 ,to: rect.width, by: elementSize) {                let hue = x / rect.width                let color = UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: 1.0)                context!.setFillColor(color.cgColor)                context!.fill(CGRect(x:x, y:y, width:elementSize,height:elementSize))            }        }    }    func getColorAtPoint(point:CGPoint) -> UIColor {        let roundedPoint = CGPoint(x:elementSize * CGFloat(Int(point.x / elementSize)),                               y:elementSize * CGFloat(Int(point.y / elementSize)))        var saturation = roundedPoint.y < self.bounds.height / 2.0 ? CGFloat(2 * roundedPoint.y) / self.bounds.height        : 2.0 * CGFloat(self.bounds.height - roundedPoint.y) / self.bounds.height        saturation = CGFloat(powf(Float(saturation), roundedPoint.y < self.bounds.height / 2.0 ? saturationExponentTop : saturationExponentBottom))        let brightness = roundedPoint.y < self.bounds.height / 2.0 ? CGFloat(1.0) : 2.0 * CGFloat(self.bounds.height - roundedPoint.y) / self.bounds.height        let hue = roundedPoint.x / self.bounds.width        return UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: 1.0)    }    func getPointForColor(color:UIColor) -> CGPoint {        var hue: CGFloat = 0.0        var saturation: CGFloat = 0.0        var brightness: CGFloat = 0.0        color.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: nil);        var yPos:CGFloat = 0        let halfHeight = (self.bounds.height / 2)        if (brightness >= 0.99) {            let percentageY = powf(Float(saturation), 1.0 / saturationExponentTop)            yPos = CGFloat(percentageY) * halfHeight        } else {            //use brightness to get Y            yPos = halfHeight + halfHeight * (1.0 - brightness)        }        let xPos = hue * self.bounds.width        return CGPoint(x: xPos, y: yPos)    }    @objc func touchedColor(gestureRecognizer: UILongPressGestureRecognizer) {        if (gestureRecognizer.state == UIGestureRecognizerState.began) {            let point = gestureRecognizer.location(in: self)            let color = getColorAtPoint(point: point)            self.delegate?.HSBColorColorPickerTouched(sender: self, color: color, point: point, state:gestureRecognizer.state)        }            }}


I went ahead and wrote a simple color picker popover in Swift. Hopefully it will help someone else out.

https://github.com/EthanStrider/ColorPickerExample

Image Picker Screenshot


Swift 3.0 version of @joel-teply's answer:

internal protocol HSBColorPickerDelegate : NSObjectProtocol {    func HSBColorColorPickerTouched(sender:HSBColorPicker, color:UIColor, point:CGPoint, state:UIGestureRecognizerState)}@IBDesignableclass HSBColorPicker : UIView {    weak internal var delegate: HSBColorPickerDelegate?    let saturationExponentTop:Float = 2.0    let saturationExponentBottom:Float = 1.3    @IBInspectable var elementSize: CGFloat = 1.0 {        didSet {            setNeedsDisplay()        }    }    private func initialize() {        self.clipsToBounds = true        let touchGesture = UILongPressGestureRecognizer(target: self, action: #selector(self.touchedColor(gestureRecognizer:)))        touchGesture.minimumPressDuration = 0        touchGesture.allowableMovement = CGFloat.greatestFiniteMagnitude        self.addGestureRecognizer(touchGesture)    }    override init(frame: CGRect) {        super.init(frame: frame)        initialize()    }    required init?(coder aDecoder: NSCoder) {        super.init(coder: aDecoder)        initialize()    }    override func draw(_ rect: CGRect) {        let context = UIGraphicsGetCurrentContext()        for y in stride(from: (0 as CGFloat), to: rect.height, by: elementSize) {            var saturation = y < rect.height / 2.0 ? CGFloat(2 * y) / rect.height : 2.0 * CGFloat(rect.height - y) / rect.height            saturation = CGFloat(powf(Float(saturation), y < rect.height / 2.0 ? saturationExponentTop : saturationExponentBottom))            let brightness = y < rect.height / 2.0 ? CGFloat(1.0) : 2.0 * CGFloat(rect.height - y) / rect.height            for x in stride(from: (0 as CGFloat), to: rect.width, by: elementSize) {                let hue = x / rect.width                let color = UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: 1.0)                context!.setFillColor(color.cgColor)                context!.fill(CGRect(x:x, y:y, width:elementSize,height:elementSize))            }        }    }    func getColorAtPoint(point:CGPoint) -> UIColor {        let roundedPoint = CGPoint(x:elementSize * CGFloat(Int(point.x / elementSize)),                                   y:elementSize * CGFloat(Int(point.y / elementSize)))        var saturation = roundedPoint.y < self.bounds.height / 2.0 ? CGFloat(2 * roundedPoint.y) / self.bounds.height            : 2.0 * CGFloat(self.bounds.height - roundedPoint.y) / self.bounds.height        saturation = CGFloat(powf(Float(saturation), roundedPoint.y < self.bounds.height / 2.0 ? saturationExponentTop : saturationExponentBottom))        let brightness = roundedPoint.y < self.bounds.height / 2.0 ? CGFloat(1.0) : 2.0 * CGFloat(self.bounds.height - roundedPoint.y) / self.bounds.height        let hue = roundedPoint.x / self.bounds.width        return UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: 1.0)    }    func getPointForColor(color:UIColor) -> CGPoint {        var hue:CGFloat=0;        var saturation:CGFloat=0;        var brightness:CGFloat=0;        color.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: nil);        var yPos:CGFloat = 0        let halfHeight = (self.bounds.height / 2)        if (brightness >= 0.99) {            let percentageY = powf(Float(saturation), 1.0 / saturationExponentTop)            yPos = CGFloat(percentageY) * halfHeight        } else {            //use brightness to get Y            yPos = halfHeight + halfHeight * (1.0 - brightness)        }        let xPos = hue * self.bounds.width        return CGPoint(x: xPos, y: yPos)    }    func touchedColor(gestureRecognizer: UILongPressGestureRecognizer){        let point = gestureRecognizer.location(in: self)        let color = getColorAtPoint(point: point)        self.delegate?.HSBColorColorPickerTouched(sender: self, color: color, point: point, state:gestureRecognizer.state)    }}