diff --git a/Colorful/Classes/ColorPicker.swift b/Colorful/Classes/ColorPicker.swift index a89bafb..bea72ce 100644 --- a/Colorful/Classes/ColorPicker.swift +++ b/Colorful/Classes/ColorPicker.swift @@ -17,6 +17,28 @@ public final class ColorPicker: UIControl { return hsvColor.uiColor } } + + public var isBrightnessSliderHidden: Bool { + set(hidden) { + setBrightness(hidden ? brightnessLevel : brightnessSlider.brightness) + brightnessSlider.isHidden = hidden + brightnessCursor.isHidden = hidden + layoutSubviews(withBrightnessSlider: !hidden) + layoutIfNeeded() + } + get { + return brightnessSlider.isHidden + } + } + + public var brightnessLevel: CGFloat { + set(level) { + setBrightness(level) + } + get { + return hsvColor.brightness + } + } private let brightnessCursor = BrightnessCursor() private let brightnessSlider = BrightnessSlider() @@ -27,6 +49,9 @@ public final class ColorPicker: UIControl { private let feedbackGenerator = UISelectionFeedbackGenerator() + private var layoutWithBrightness: [NSLayoutConstraint] = [] + private var layoutWithoutBrightness: [NSLayoutConstraint] = [] + public override init(frame: CGRect) { super.init(frame: frame) setup() @@ -42,6 +67,8 @@ public final class ColorPicker: UIControl { addSubview(brightnessSlider) addSubview(brightnessCursor) addSubview(colorMapCursor) + + setupConstraints() let colorMapPan = UIPanGestureRecognizer(target: self, action: #selector(self.handleColorMapPan(pan:))) colorMapPan.delegate = self @@ -55,6 +82,40 @@ public final class ColorPicker: UIControl { feedbackGenerator.prepare() } + + private func setupConstraints() { + colorMap.translatesAutoresizingMaskIntoConstraints = false + brightnessCursor.translatesAutoresizingMaskIntoConstraints = false + brightnessSlider.translatesAutoresizingMaskIntoConstraints = false + + let margin: CGFloat = 12 + let brightnessWidth: CGFloat = 72 + let cursorHeight:CGFloat = 28 + + layoutWithBrightness = [ + colorMap.topAnchor.constraint(equalTo: topAnchor, constant: margin), + colorMap.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -margin), + colorMap.leftAnchor.constraint(equalTo: leftAnchor, constant: margin), + colorMap.rightAnchor.constraint(equalTo: brightnessSlider.leftAnchor, constant: -margin), + + brightnessSlider.widthAnchor.constraint(equalToConstant: brightnessWidth), + brightnessSlider.topAnchor.constraint(equalTo: topAnchor), + brightnessSlider.bottomAnchor.constraint(equalTo: bottomAnchor), + brightnessSlider.rightAnchor.constraint(equalTo: rightAnchor, constant: -margin), + + brightnessCursor.centerYAnchor.constraint(equalTo: brightnessSlider.centerYAnchor), + brightnessCursor.centerXAnchor.constraint(equalTo: brightnessSlider.centerXAnchor), + brightnessCursor.heightAnchor.constraint(equalToConstant: cursorHeight), + brightnessCursor.widthAnchor.constraint(equalToConstant: brightnessWidth), + ] + + layoutWithoutBrightness = [ + colorMap.topAnchor.constraint(equalTo: topAnchor, constant: margin), + colorMap.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -margin), + colorMap.leftAnchor.constraint(equalTo: leftAnchor, constant: margin), + colorMap.rightAnchor.constraint(equalTo: rightAnchor, constant: -margin), + ] + } public func set(color: UIColor, colorSpace: HRColorSpace) { self.colorSpace = colorSpace @@ -66,25 +127,21 @@ public final class ColorPicker: UIControl { } public override func layoutSubviews() { + self.layoutSubviews(withBrightnessSlider: !self.brightnessSlider.isHidden) super.layoutSubviews() - - let margin: CGFloat = 12 - let brightnessSliderWidth: CGFloat = 72 - let colorMapSize = min(bounds.width - brightnessSliderWidth - margin * 3, bounds.height - 2 * margin) - - let colorMapX = (bounds.width - (colorMapSize + margin * 2 + brightnessSliderWidth)) / 2 - - colorMap.frame = CGRect(x: colorMapX, y: (bounds.height - colorMapSize)/2, width: colorMapSize + margin * 2, height: colorMapSize) - brightnessSlider.frame = CGRect(x: colorMap.frame.maxX, y: (bounds.height - colorMapSize)/2, - width: brightnessSliderWidth, height: colorMapSize) - - let brightnessCursorSize = CGSize(width: brightnessSliderWidth, height: 28) - brightnessCursor.frame = CGRect(x: colorMap.frame.maxX, - y: (bounds.height - brightnessCursorSize.height)/2, - width: brightnessCursorSize.width, height: brightnessCursorSize.height) mapColorToView(initialize: true) } + private func layoutSubviews(withBrightnessSlider: Bool) { + if withBrightnessSlider { + NSLayoutConstraint.deactivate(layoutWithoutBrightness) + NSLayoutConstraint.activate(layoutWithBrightness) + } else { + NSLayoutConstraint.deactivate(layoutWithBrightness) + NSLayoutConstraint.activate(layoutWithoutBrightness) + } + } + private func mapColorToView(initialize: Bool = false) { brightnessCursor.set(hsv: hsvColor) colorMap.set(brightness: hsvColor.brightness) @@ -96,6 +153,13 @@ public final class ColorPicker: UIControl { } } + private func setBrightness(_ brightness: CGFloat) { + hsvColor = hsvColor.hueAndSaturation.with(brightness: brightness) + mapColorToView() + feedbackIfNeeds() + sendActionIfNeeds() + } + @objc private func handleColorMapPan(pan: UIPanGestureRecognizer) { switch pan.state { @@ -151,9 +215,6 @@ extension ColorPicker: UIGestureRecognizerDelegate { extension ColorPicker: BrightnessSliderDelegate { func handleBrightnessChanged(slider: BrightnessSlider) { - hsvColor = hsvColor.hueAndSaturation.with(brightness: slider.brightness) - mapColorToView() - feedbackIfNeeds() - sendActionIfNeeds() + setBrightness(slider.brightness) } } diff --git a/Example/Colorful/Base.lproj/Main.storyboard b/Example/Colorful/Base.lproj/Main.storyboard index cd62e39..f02d778 100644 --- a/Example/Colorful/Base.lproj/Main.storyboard +++ b/Example/Colorful/Base.lproj/Main.storyboard @@ -1,9 +1,10 @@ - + - + + @@ -21,14 +22,14 @@ - + @@ -36,42 +37,42 @@ - - - - + - - + + - + - - + + + + + + + + + + + + + + + + + + + + + + @@ -90,30 +119,46 @@ + + + + + + - + + + + + + - + - + + + + + + diff --git a/Example/Colorful/ViewController.swift b/Example/Colorful/ViewController.swift index e07ff92..1e8d217 100644 --- a/Example/Colorful/ViewController.swift +++ b/Example/Colorful/ViewController.swift @@ -13,7 +13,9 @@ class ViewController: UIViewController { @IBOutlet weak var colorPicker: ColorPicker! @IBOutlet weak var label: UILabel! - @IBOutlet weak var uiSwitch: UISwitch! + @IBOutlet weak var sRGBSwitch: UISwitch! + @IBOutlet weak var brightnessSwitch: UISwitch! + @IBOutlet weak var brightnessSlider: UISlider! @IBOutlet weak var colorSpaceLabel: UILabel! var colorSpace: HRColorSpace = .sRGB @@ -24,6 +26,7 @@ class ViewController: UIViewController { colorPicker.set(color: UIColor(displayP3Red: 1.0, green: 1.0, blue: 0, alpha: 1), colorSpace: colorSpace) updateColorSpaceText() handleColorChanged(picker: colorPicker) + brightnessSlider.isHidden = !colorPicker.isBrightnessSliderHidden } @objc func handleColorChanged(picker: ColorPicker) { @@ -46,12 +49,25 @@ class ViewController: UIViewController { } @IBAction func handleSwitchAction(_ sender: UISwitch) { - colorSpace = sender.isOn ? .extendedSRGB : .sRGB - colorPicker.set(color: colorPicker.color, colorSpace: colorSpace) - updateColorSpaceText() - handleColorChanged(picker: colorPicker) + switch sender.tag { + case 0: + colorSpace = sender.isOn ? .extendedSRGB : .sRGB + colorPicker.set(color: colorPicker.color, colorSpace: colorSpace) + updateColorSpaceText() + handleColorChanged(picker: colorPicker) + case 1: + colorPicker.isBrightnessSliderHidden.toggle() + brightnessSlider.isHidden = !colorPicker.isBrightnessSliderHidden + brightnessSlider.value = Float(colorPicker.brightnessLevel) + default: + break + } } - + + @IBAction func handleSliderAction(_ sender: UISlider) { + colorPicker.brightnessLevel = CGFloat(sender.value) + } + func updateColorSpaceText() { switch colorSpace { case .extendedSRGB: diff --git a/README.md b/README.md index 5143bde..e315b95 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,13 @@ view.addSubview(colorPicker) You can receive `.valueChanged` event when user changes color. +You can hide the brightness slider and set the brightness level programmatically: + +```swift +colorPicker.isBrightnessSliderHidden = true +colorPicker.brightnessLevel = 1.0 +``` + ## Reason why you choose colorful ### Beautiful UI with haptic feedback.