【问题标题】:Simple swift color picker popover (iOS)简单的快速颜色选择器弹出框(iOS)
【发布时间】:2015-01-28 06:39:36
【问题描述】:

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

【问题讨论】:

    标签: ios swift popover color-picker color-palette


    【解决方案1】:

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

    元素大小=1(默认)

    元素大小=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)
            }        
        }
    }
    

    【讨论】:

    • 我喜欢您将代码放在 Stack Overflow 中,而不是链接到某个 github 项目。
    • 这里缺少的一件事是灰度。
    • 看起来很漂亮,但我无法将它调整到我现有的 Objective C 项目中。事实上,我在包含上述代码的 swift 文件中遇到错误。我已经导入了 UIKit,但在我看来 Swift 改变了它的语法?上面的代码与 Swift 2.3 兼容吗?我使用 Xcode 8.1。如果我对 Swift 不熟悉,我很抱歉。谢谢你的建议。
    • 当我回到这一点时,我也会添加灰度。我们现在使用 swift 3.0,但如果有人想提供他们的翻译代码,我会更新它。
    • 认为颜色返回错误是因为 longPressGesture 被调用两次错误计算,更新了代码
    【解决方案2】:

    我继续用 Swift 编写了一个简单的颜色选择器弹出框。希望它会帮助其他人。

    https://github.com/EthanStrider/ColorPickerExample

    【讨论】:

    • 我不知道这个答案的答案在哪里。
    • 问。你是如何生成这个特定的调色板的?它看起来像是程序颜色和手工挑选颜色的组合。整体效果比平时使用的 RGB 彩虹光谱要好很多。
    • 说实话,我想我在网上找到了一个调色板,它只是一个艺术家创作的图像。然后,我使用吸管工具手动对所有图像颜色进行采样并获得它们的 RGB 值。您可以在此处找到所有值:github.com/EthanStrider/ColorPickerExample/blob/master/…
    • 谢谢 - 完美运行并转换为 swift 5 没有太多问题。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      import UIKit
      
      
      class ColorPickerView : UIView {
      
      var onColorDidChange: ((_ color: UIColor) -> ())?
      
      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)
          }
      }
      
      
      @objc func touchedColor(gestureRecognizer: UILongPressGestureRecognizer){
          let point = gestureRecognizer.location(in: self)
          let color = getColorAtPoint(point: point)
      
          self.onColorDidChange?(color)
        }
      }
      

      用法:

          let colorPickerView = ColorPickerView()
          colorPickerView.onColorDidChange = { [weak self] color in
              DispatchQueue.main.async {
      
                  // use picked color for your needs here...
                  self?.view.backgroundColor = color
              }
      
          }
      
          // add it to some view and set constraints
          ...
      

      【讨论】:

      • 你能解释一下如何在VC中使用代码吗?或发布一个如何完成的示例?
      • 更新了我的答案。为简单起见,去掉了委托。
      • MichaelRos,我按以下方式尝试了您的代码,但单击按钮时没有任何反应。我做错了什么?类 CustomizationViewController: UIViewController { @IBAction func backgroundColorSelector(_ sender: Any) { let colorPickerView = ColorPickerView() colorPickerView.onColorDidChange = { [weak self] 颜色 in DispatchQueue.main.async { self?.view.backgroundColor = color } } } }
      • 通过添加 UIView 并分配给 ColorPickerView 类使其工作。谢谢。
      • @Yan 我还在视图控制器的顶部添加了 UIView,但我什么也没得到
      【解决方案5】:

      Apple 现在在 iOS 14 中实现了标准 UIColorPickerViewController 和关联的 UIColorWell,这是一个自动调出 UIColorPicker 以选择颜色的色板。

      您可以通过使用 Xcode 12 或更高版本(针对 iOS 14+)创建 Swift App 项目来测试 ColorPicker,然后尝试以下简单代码:

      import SwiftUI
      
      struct ContentView: View {
          @State private var bgColor = Color.white
      
          var body: some View {
              VStack {
                  ColorPicker("Set the background color",
                              selection: $bgColor,
                              supportsOpacity: true)
              }
              .frame(maxWidth: .infinity, maxHeight: .infinity)
              .background(bgColor)
          }
      }
      

      supportsOpacity 更改为false 以去掉不透明度滑块,只允许完全不透明的颜色。

      ColorPicker 显示两种不同的选择模式:

      没有 alpha 的颜色选择器:

      【讨论】:

      • 如何在 UIViewController 类中将它与常规 Swift 一起使用?
      【解决方案6】:

      感谢您的起点。

      我从那里得到它,并用自定义 UIView 和一些绘图代码编写了一个完整的 Color PickerViewController。

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

      https://github.com/Christian1313/iOS_Swift_ColorPicker

      【讨论】:

        【解决方案7】:

        ColorPickerViewImage

        根据 Christian1313 的回答,我添加了深色

        @IBDesignable final public class SwiftColorView: UIView {
        
        weak var colorSelectedDelegate: ColorDelegate?
        
        @IBInspectable public var numColorsX:Int =  10 {
            didSet {
                setNeedsDisplay()
            }
        }
        
        @IBInspectable public var numColorsY:Int = 18 {
            didSet {
                setNeedsDisplay()
            }
        }
        
        @IBInspectable public var coloredBorderWidth:Int = 10 {
            didSet {
                setNeedsDisplay()
            }
        }
        
        @IBInspectable public var showGridLines:Bool = false {
            didSet {
                setNeedsDisplay()
            }
        }
        
        weak var delegate: SwiftColorPickerDataSource?
        
        public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            guard let touch = touches.first else { return }
            let location = touch.location(in: self)
        
            colorSelectedDelegate?.setStroke(color: colorAtPoint(point: location))
        }
        
        public override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
            guard let touch = touches.first else { return }
            let location = touch.location(in: self)
        
            colorSelectedDelegate?.setStroke(color: colorAtPoint(point: location))
        }
        
        public override func draw(_ rect: CGRect) {
            super.draw(rect)
            let lineColor = UIColor.gray
            let pS = patternSize()
            let w = pS.w
            let h = pS.h
        
            for y in 0..<numColorsY
            {
                for x in 0..<numColorsX
                {
                    let path = UIBezierPath()
                    let start = CGPoint(x: CGFloat(x)*w+CGFloat(coloredBorderWidth), y: CGFloat(y)*h+CGFloat(coloredBorderWidth))
                    path.move(to: start);
                    path.addLine(to: CGPoint(x: start.x+w, y: start.y))
                    path.addLine(to: CGPoint(x: start.x+w, y: start.y+h))
                    path.addLine(to: CGPoint(x: start.x, y: start.y+h))
                    path.addLine(to: start)
                    path.lineWidth = 0.25
                    colorForRectAt(x: x,y:y).setFill();
        
                    if (showGridLines)
                    {
                        lineColor.setStroke()
                    }
                    else
                    {
                        colorForRectAt(x: x, y: y).setStroke();
                    }
                    path.fill();
                    path.stroke();
                }
            }
        }
        
        private func colorForRectAt(x: Int, y: Int) -> UIColor
        {
        
            if let ds = delegate {
                return ds.colorForPalletIndex(x: x, y: y, numXStripes: numColorsX, numYStripes: numColorsY)
            } else {
        
                var hue:CGFloat = CGFloat(x) / CGFloat(numColorsX)
                var fillColor = UIColor.white
                if (y==0)
                {
                    if (x==(numColorsX-1))
                    {
                        hue = 1.0;
                    }
                    fillColor = UIColor(white: hue, alpha: 1.0);
                }
                else
                {
                    if y < numColorsY / 2 {
                        //dark
                        let length = numColorsY / 2
                        let brightness: CGFloat = CGFloat(y) / CGFloat(length)
                        fillColor = UIColor(hue: hue, saturation: 1.0, brightness: brightness, alpha: 1.0)
                    } else if y == numColorsY / 2 {
                        // normal
                        fillColor = UIColor(hue: hue, saturation: 1.0, brightness: 1.0, alpha: 1.0)
                    } else {
                        // light
                        let length = numColorsY / 2 - 1
                        let offset = y - length - 1
                        let sat:CGFloat = CGFloat(1.0) - CGFloat(offset) / CGFloat(length + 1)
                        print("sat", sat)
                        fillColor = UIColor(hue: hue, saturation: sat, brightness: 1.0, alpha: 1.0)
                    }
                }
                return fillColor
            }
        }
        
        func colorAtPoint(point: CGPoint) -> UIColor
        {
            let pS = patternSize()
            let w = pS.w
            let h = pS.h
            let x = (point.x-CGFloat(coloredBorderWidth))/w
            let y = (point.y-CGFloat(coloredBorderWidth))/h
            return colorForRectAt(x: Int(x), y:Int(y))
        }
        
        private func patternSize() -> (w: CGFloat, h:CGFloat)
        {
            let width = self.bounds.width-CGFloat(2*coloredBorderWidth)
            let height = self.bounds.height-CGFloat(2*coloredBorderWidth)
        
            let w = width/CGFloat(numColorsX)
            let h = height/CGFloat(numColorsY)
            return (w,h)
        }
        
        public override func prepareForInterfaceBuilder()
        {
            print("Compiled and run for IB")
        }
        

        }

        【讨论】:

          【解决方案8】:

          使用 Michael Ros 的答案,

          如果您想通过objective-c viewcontroller 使用此视图,您可以简单地创建一个名为ColorPickerView 的新swift 文件,然后在情节提要上的viewcontroller 中添加一个uiview,然后选择ColorPickerView 作为它的类名。然后让您的视图控制器成为名称为@“colorIsPicking”的通知观察者

          [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateColor) name:@"colorIsPicked" object:nil];
          

          ColorPickerView.swift 的代码

          class ColorPickerView : UIView {
          
          @objc public lazy var onColorDidChange: ((_ color: UIColor) -> ()) = {
                     
              //send a notification for the caller view to update its elements if necessery
              NotificationCenter.default.post(name: Notification.Name("colorIsPicked"), object: nil)
          
          }
          
          
          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 = 10.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)
              }
          }
          
          
          @objc func touchedColor(gestureRecognizer: UILongPressGestureRecognizer){
              let point = gestureRecognizer.location(in: self)
              let color = getColorAtPoint(point: point)
              
              self.onColorDidChange(color)
          }
           }
          

          【讨论】:

            【解决方案9】:

            我快速添加了代码以使用 iOS 14 中发布的 Apple 颜色选择器为 ViewController 实现颜色选择器。确保您的部署信息至少为 IOS 14.0 或更高版本。参考https://developer.apple.com/documentation/uikit/uicolorpickerviewcontroller

            将颜色选择器委托添加到类中,并声明一个颜色选择器对象:

            class ViewController: UIViewController, UIColorPickerViewControllerDelegate  {
                
                let colorPicker = UIColorPickerViewController()
            

            在 viewDidLoad 的最后,我将 colorPicker 委托设置为 self

                    colorPicker.delegate = self
            
                } // ends viewDidLoad
            

            我使用一个颜色选择器为几个不同的对象选择颜色。当我向用户展示颜色选择器时,我将一个布尔标志设置为 true 以指示颜色选择器显示的原因。

                    resetAllColorChangeFlags() // First make sure all the booleans are false for robust design
            
                    changingScreenBackgroundColor = true
            
                    present(colorPicker, animated: true, completion: nil)
            

            我添加了处理 colorPickerViewControllerDidSelectColor 和 colorPickerViewControllerDidFinish 的 API

            colorPickerViewControllerDidSelectColor 检查布尔标志,并为适当的对象设置颜色属性。如果颜色应用于图层中的边框颜色,则使用 cgColor。

                func colorPickerViewControllerDidSelectColor(_ viewController: UIColorPickerViewController) {
                    
                    if changingScreenBackgroundColor
                    {
                        self.view.backgroundColor = viewController.selectedColor
                    }
                    if addingATintCircle
                    {
                        pointerToThisTintView.backgroundColor = viewController.selectedColor
                    }
                    if changingTextBackgroundColor
                    {
                        pointerToTextObjectSelected.backgroundColor = viewController.selectedColor
                    }
                    if changingTextColor
                    {
                        pointerToTextObjectSelected.textColor = viewController.selectedColor
                    }
                    if changingTextBorderColor
                    {
                        pointerToTextObjectSelected.layer.borderColor = viewController.selectedColor.cgColor
                    }
                    if changingPhotoBorderColor
                    {
                        pointerToPhotoObjectSelected.layer.borderColor = viewController.selectedColor.cgColor
                    }
                    if changingCameraBorderColor {
                        cameraView.layer.borderColor = viewController.selectedColor.cgColor
                    }
                } // ends colorPickerViewControllerDidSelectColor
            

            colorPickerViewControllerDidFinish 仅用于重置我的所有布尔标志,这些标志指示颜色选择器为何呈现给用户。

            
                func colorPickerViewControllerDidFinish(_ viewController: UIColorPickerViewController)
                {
                    resetAllColorChangeFlags()
            
                } // ends colorPickerViewControllerDidFinish
            

            这是我的重置程序:

                func resetAllColorChangeFlags()
                {
                    changingFunTextColor = false
                    changingFunTextFirstColorForGradient = false
                    changingFunTextSecondColorForGradient = false
                    changingScreenBackgroundColor = false
                    changingTextBackgroundColor = false
                    changingTextColor = false
                    changingTextBorderColor = false
                    changingPhotoBorderColor = false
                    changingCameraBorderColor = false
                    addingATintToAPhotoObject = false
                    addingATintCircle = false
                    addingAColorForGradients = false
                    
                } // ends resetAllColorChangeFlags
            

            【讨论】:

              猜你喜欢
              • 2015-01-11
              • 2019-12-30
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-07-01
              • 2011-11-02
              相关资源
              最近更新 更多