Search code examples
iosswiftcolorscolor-picker

Retrieving UIColor from another class Delegate


I am trying to implement the class HSBColorPicker in my app. I have everything compiling and running like I want up to this point but where I am stuck is trying to get the color information from the HSBColorPicker class and use it in my other classes. Here is what my app looks like right now:

Color Picker App

My goal is that the user touches anywhere on the color spectrum at the top and that color is picked and is set to the current color. The code for the color picker works, as does the code for my view controller. Basically what I cannot figure out is how to retrieve the UIColor that the user has selected by tapping on the spectrum. More specifically I need to extract the Red, Green, and Blue values from that UIColor.

Once I have those values I can take it from there but I am stumped as to how to get the UIColor from the HSBColorPicker class in my ColorsViewController class.

Here is the HSBColorPicker class:

//
//  HSBColorPicker.swift
//  LED Ring App
//
//  Created by Blake Fabiani on 9/22/16.
//  Copyright © 2016 Blake Fabiani. All rights reserved.
//
import UIKit

internal protocol HSBColorPickerDelegate : NSObjectProtocol {
    func HSBColorColorPickerTouched(sender:HSBColorPicker, color:UIColor, point:CGPoint, state:UIGestureRecognizerState)
}

@IBDesignable
class 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(HSBColorPicker.touchedColor(_:)))
        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, 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, 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)
    }
}

And Here is the ColorsViewController

//
//  ColorsViewController.swift
//  LED Ring App
//
//  Created by Blake Fabiani on 9/13/16.
//  Copyright © 2016 Blake Fabiani. All rights reserved.
//

import UIKit

var redColor: float_t = 0
var greenColor: float_t = 0
var blueColor: float_t = 0

class ColorsViewController: UIViewController {

    @IBOutlet weak var redSlider: UISlider!
    @IBOutlet weak var greenSlider: UISlider!
    @IBOutlet weak var blueSlider: UISlider!

    @IBOutlet weak var ColorPickerImageView: UIImageView!

    @IBOutlet weak var redColorLabel: UILabel!
    @IBOutlet weak var greenColorLabel: UILabel!
    @IBOutlet weak var blueColorLabel: UILabel!

    @IBOutlet weak var currentColorButton: UIButton!

    @IBAction func redSliderAction(_ sender: UISlider) {
        changeColors()
    }
    @IBAction func greenSliderAction(_ sender: UISlider) {
        changeColors()
    }
    @IBAction func blueSliderAction(_ sender: UISlider) {
        changeColors()
    }

    func chageCurrentColorImage() {
        currentColorButton.backgroundColor = UIColor(red: CGFloat(redColor/Float(255.0)), green: CGFloat(greenColor/Float(255)), blue: CGFloat(blueColor/Float(255)), alpha: 1.0)
        changeSliderLabel()
    }
    func changeColors() {
        redColor = redSlider.value
        greenColor = greenSlider.value
        blueColor = blueSlider.value
        chageCurrentColorImage()
    }

    func changeSliderValue() {
        redSlider.value = redColor
        greenSlider.value = greenColor
        blueSlider.value = blueColor
    }

    func changeSliderLabel() {
        let roundedRed = String(format: "%0.0f",(redColor))
        let roundedGreen = String(format: "%0.0f",(greenColor))
        let roundedBlue = String(format: "%0.0f",(blueColor))
        redColorLabel.text = "Red: \(roundedRed)"
        greenColorLabel.text = "Green: \(roundedGreen)"
        blueColorLabel.text = "Blue: \(roundedBlue)"

    }

    override func viewDidLoad() {
        super.viewDidLoad()
        chageCurrentColorImage()
        changeSliderValue()
    }
}

Solution

  • Make the ColorsViewController confirm to the HSBColorPickerDelegate. And implement that method and store the value in ColorsViewController. Also, I don't see that you are using the HSBColorPicker in ColorsViewController.