'iOS 14 UIColorPicker eyedropper tool not returning selected color

I am currently trying to implement the new iOS 14 UIColorPicker. Everything works great, except the eye dropper functionality of the UIColorPicker. After selecting the the eye dropper and sampling a color, the default behavior should be to re-open the UIColorPicker with your selected color as the active one. For some reason, this does not happen. Here is my implementation, its pretty standard, so I'm not sure why the eyedropper isnt behaving as expected.

I have these functions that are passed as the selectors for when I have some UI elements pressed

@objc func pickColorSky(sender: UIControl){
  presentColorPicker(tag: 1, sender: sender)
}

@objc func pickColorBackground(sender: UIControl){
  presentColorPicker(tag: 2, sender: sender)
}
  
@objc func pickColorGround(sender: UIControl){
  presentColorPicker(tag: 3, sender: sender)
}

Here is the function that presents the UIColorPickerView itself

@objc private func presentColorPicker(tag: Int, sender: UIControl){
    let vc = UIColorPickerViewController()
    vc.supportsAlpha = false
    vc.delegate = self
    vc.view.tag = tag
    vc.modalPresentationStyle = .popover
    vc.popoverPresentationController?.sourceView = sender
    vc.popoverPresentationController?.sourceRect = sender.bounds
    self.present(vc, animated: true)
}

And the delegate methods to handle the interacting with the color picker

extension myViewController: UIColorPickerViewControllerDelegate {
  
  func colorPickerViewControllerDidFinish(_ viewController: UIColorPickerViewController) {
    guard let options = editor?.apiView?.getRenderingOptions() else { return }
      if viewController.view.tag == 1 {
        let newColor = getMobileApiColor(color: viewController.selectedColor)
        options.skyColor = newColor
        skyRow.color.backgroundColor = newColor.uiColor
      }
      else if viewController.view.tag == 2 {
        let newColor = getMobileApiColor(color: viewController.selectedColor)
        options.backgroundColor = newColor
        backgroundRow.color.backgroundColor = newColor.uiColor
      }
      else if viewController.view.tag == 3 {
        let newColor = getMobileApiColor(color: viewController.selectedColor)
        options.groundColor = newColor
        groundRow.color.backgroundColor = newColor.uiColor
      }
      editor?.modelView?.setNeedsDisplay()
  }


Solution 1:[1]

Try this method colorPickerViewControllerDidSelectColor

extension ViewController: UIColorPickerViewControllerDelegate {
    
    //  Called once you have finished picking the color.
    func colorPickerViewControllerDidFinish(_ viewController: UIColorPickerViewController) {
        self.view.backgroundColor = viewController.selectedColor
        
    }
    
    //  Called on every color selection done in the picker.
    func colorPickerViewControllerDidSelectColor(_ viewController: UIColorPickerViewController) {
            self.view.backgroundColor = viewController.selectedColor
    }
}

Solution 2:[2]

You need to hold on to the picker object as a class member like this:

    private lazy var colorPicker = makeColorPicker()
private func makeColorPicker() -> UIColorPickerViewController {
        let vc = UIColorPickerViewController()
        vc.delegate = self
        vc.supportsAlpha = false
        return vc
}

Otherwise, it is removed from memory before you complete the eye-dropper step.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Yogesh Patel
Solution 2 James Grote