ios swift popover color-picker color-palette

Selector de colores rápido y simple emergente(iOS)



swift popover (5)

¿Existe una forma sencilla de implementar un selector de color en Swift? ¿Hay bibliotecas integradas o elementos de UI que pueda aprovechar para este propósito? Vi algunos selectores de color escritos en objetivo-c, pero tenían varios años y me preguntaba si habría algo más reciente.


Aquí hay uno que hice, que es tan simple como se pone. Es solo una UIView liviana que le permite especificar el tamaño del elemento en caso de que quiera regiones bloqueadas (elementSize> 1). Se dibuja en el generador de interfaces para que pueda establecer el tamaño del elemento y ver las consecuencias. Solo establezca una de sus vistas en el generador de interfaces para esta clase y luego establezca como delegado. Le dirá cuándo alguien lo pulsa o arrastra y el uicolor en esa ubicación. Se atraerá a sus propios límites y no hay necesidad de nada más que de esta clase, no se requiere imagen.

Tamaño del elemento = 1 (Predeterminado)

Tamaño del elemento = 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) } } }


Basado en el código de Joel Teply (Swift 4), con una barra gris en la parte superior:

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


Gracias por el punto de partida.

Lo tomé de allí y escribí un completo Color PickerViewController con una vista UIV personalizada y un código de dibujo.

Hice el UIView personalizado @IBDesignable para que pueda ser renderizado en InterfaceBuilder.

https://github.com/Christian1313/iOS_Swift_ColorPicker



Swift 3.0 versión de la respuesta de :

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