简单快捷的颜色选择器popover(iOS)

是否有一种简单的方法可以在swift中实现颜色选择器弹出框? 是否有可用于此目的的内置库或UI元素? 我看到一些用objective-c写的颜色选择器,但它们已经好几年了,我想知道是否有更新的东西。

这是我制作的一个,它就像它一样简单。 它只是一个轻量级的UIView,允许您指定元素大小,以防您想要阻塞区域(elementSize> 1)。 它在界面构建器中绘制,因此您可以设置元素大小并查看结果。 只需将界面构建器中的一个视图设置为此类,然后将自己设置为委托。 当有人点击或拖动它并在该位置使用uicolor时它会告诉你。 它将自己绘制到自己的边界,除了这个类之外不需要任何其他东西,不需要图像。

元素大小= 1(默认) 元素大小= 1

元素大小= 10
元素大小= 10

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(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) } } } 

我继续在Swift中写了一个简单的颜色选择器popover。 希望它会帮助其他人。

https://github.com/EthanStrider/ColorPickerExample

图像选择器截图

Swift 3.0版@ joel-teply的回答:

 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(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) } } 

谢谢你的起点。

我从那里开始编写了一个带有自定义UIView和一些绘图代码的complte Color PickerViewController。

我制作了自定义UIView @IBDesignable,因此它可以在InterfaceBuilder中呈现。

https://github.com/Christian1313/iOS_Swift_ColorPicker

基于Joel Teply代码(Swift 4),顶部带有灰色条:

 import UIKit protocol ColorPickerDelegate: class{ func colorDidChange(color: UIColor) } class ColorPickerView : UIView { weak var delegate: ColorPickerDelegate? let saturationExponentTop:Float = 2.0 let saturationExponentBottom:Float = 1.3 let grayPaletteHeightFactor: CGFloat = 0.1 var rect_grayPalette = CGRect.zero var rect_mainPalette = CGRect.zero // adjustable var elementSize: CGFloat = 1.0 { didSet { setNeedsDisplay() } } override init(frame: CGRect) { super.init(frame: frame) setup() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setup() } private func setup() { self.clipsToBounds = true let touchGesture = UILongPressGestureRecognizer(target: self, action: #selector(self.touchedColor(gestureRecognizer:))) touchGesture.minimumPressDuration = 0 touchGesture.allowableMovement = CGFloat.greatestFiniteMagnitude self.addGestureRecognizer(touchGesture) } override func draw(_ rect: CGRect) { let context = UIGraphicsGetCurrentContext() rect_grayPalette = CGRect(x: 0, y: 0, width: rect.width, height: rect.height * grayPaletteHeightFactor) rect_mainPalette = CGRect(x: 0, y: rect_grayPalette.maxY, width: rect.width, height: rect.height - rect_grayPalette.height) // gray palette for y in stride(from: CGFloat(0), to: rect_grayPalette.height, by: elementSize) { for x in stride(from: (0 as CGFloat), to: rect_grayPalette.width, by: elementSize) { let hue = x / rect_grayPalette.width let color = UIColor(white: hue, alpha: 1.0) context!.setFillColor(color.cgColor) context!.fill(CGRect(x:x, y:y, width:elementSize, height:elementSize)) } } // main palette for y in stride(from: CGFloat(0), to: rect_mainPalette.height, by: elementSize) { var saturation = y < rect_mainPalette.height / 2.0 ? CGFloat(2 * y) / rect_mainPalette.height : 2.0 * CGFloat(rect_mainPalette.height - y) / rect_mainPalette.height saturation = CGFloat(powf(Float(saturation), y < rect_mainPalette.height / 2.0 ? saturationExponentTop : saturationExponentBottom)) let brightness = y < rect_mainPalette.height / 2.0 ? CGFloat(1.0) : 2.0 * CGFloat(rect_mainPalette.height - y) / rect_mainPalette.height for x in stride(from: (0 as CGFloat), to: rect_mainPalette.width, by: elementSize) { let hue = x / rect_mainPalette.width let color = UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: 1.0) context!.setFillColor(color.cgColor) context!.fill(CGRect(x:x, y: y + rect_mainPalette.origin.y, width: elementSize, height: elementSize)) } } } func getColorAtPoint(point: CGPoint) -> UIColor { var roundedPoint = CGPoint(x:elementSize * CGFloat(Int(point.x / elementSize)), y:elementSize * CGFloat(Int(point.y / elementSize))) let hue = roundedPoint.x / self.bounds.width // main palette if rect_mainPalette.contains(point) { // offset point, because rect_mainPalette.origin.y is not 0 roundedPoint.y -= rect_mainPalette.origin.y var saturation = roundedPoint.y < rect_mainPalette.height / 2.0 ? CGFloat(2 * roundedPoint.y) / rect_mainPalette.height : 2.0 * CGFloat(rect_mainPalette.height - roundedPoint.y) / rect_mainPalette.height saturation = CGFloat(powf(Float(saturation), roundedPoint.y < rect_mainPalette.height / 2.0 ? saturationExponentTop : saturationExponentBottom)) let brightness = roundedPoint.y < rect_mainPalette.height / 2.0 ? CGFloat(1.0) : 2.0 * CGFloat(rect_mainPalette.height - roundedPoint.y) / rect_mainPalette.height return UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: 1.0) } // gray palette else{ return UIColor(white: hue, 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) } */ @objc func touchedColor(gestureRecognizer: UILongPressGestureRecognizer){ let point = gestureRecognizer.location(in: self) let color = getColorAtPoint(point: point) self.delegate?.colorDidChange(color: color) } }