Simple swift color picker popover (iOS)

前端 未结 8 1171
被撕碎了的回忆
被撕碎了的回忆 2020-12-12 13:30

Is there is a simple way to implement a color picker popover in swift? Are there any built-in libraries or UI elements that I could leverage for this purpose? I saw some c

8条回答
  •  爱一瞬间的悲伤
    2020-12-12 13:34

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

提交回复
热议问题