-
-
Save Amzd/62160c84a29ae93d565b20f63b9e3247 to your computer and use it in GitHub Desktop.
import SwiftUI | |
@available(iOS 14.0, *) | |
public struct ColorPickerWithoutLabel: UIViewRepresentable { | |
@Binding var selection: Color | |
var supportsAlpha: Bool = true | |
public init(selection: Binding<Color>, supportsAlpha: Bool = true) { | |
self._selection = selection | |
self.supportsAlpha = supportsAlpha | |
} | |
public func makeUIView(context: Context) -> UIColorWell { | |
let well = UIColorWell() | |
well.supportsAlpha = supportsAlpha | |
return well | |
} | |
public func updateUIView(_ uiView: UIColorWell, context: Context) { | |
uiView.selectedColor = UIColor(selection) | |
} | |
} | |
extension View { | |
@available(iOS 14.0, *) | |
public func colorPickerSheet(isPresented: Binding<Bool>, selection: Binding<Color>, supportsAlpha: Bool = true, title: String? = nil) -> some View { | |
self.background(ColorPickerSheet(isPresented: isPresented, selection: selection, supportsAlpha: supportsAlpha, title: title)) | |
} | |
} | |
@available(iOS 14.0, *) | |
private struct ColorPickerSheet: UIViewRepresentable { | |
@Binding var isPresented: Bool | |
@Binding var selection: Color | |
var supportsAlpha: Bool | |
var title: String? | |
func makeCoordinator() -> Coordinator { | |
Coordinator(selection: $selection, isPresented: $isPresented) | |
} | |
class Coordinator: NSObject, UIColorPickerViewControllerDelegate, UIAdaptivePresentationControllerDelegate { | |
@Binding var selection: Color | |
@Binding var isPresented: Bool | |
var didPresent = false | |
init(selection: Binding<Color>, isPresented: Binding<Bool>) { | |
self._selection = selection | |
self._isPresented = isPresented | |
} | |
func colorPickerViewControllerDidSelectColor(_ viewController: UIColorPickerViewController) { | |
selection = Color(viewController.selectedColor) | |
} | |
func colorPickerViewControllerDidFinish(_ viewController: UIColorPickerViewController) { | |
isPresented = false | |
didPresent = false | |
} | |
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { | |
isPresented = false | |
didPresent = false | |
} | |
} | |
func getTopViewController(from view: UIView) -> UIViewController? { | |
guard var top = view.window?.rootViewController else { | |
return nil | |
} | |
while let next = top.presentedViewController { | |
top = next | |
} | |
return top | |
} | |
func makeUIView(context: Context) -> UIView { | |
let view = UIView() | |
view.isHidden = true | |
return view | |
} | |
func updateUIView(_ uiView: UIView, context: Context) { | |
if isPresented && !context.coordinator.didPresent { | |
let modal = UIColorPickerViewController() | |
modal.selectedColor = UIColor(selection) | |
modal.supportsAlpha = supportsAlpha | |
modal.title = title | |
modal.delegate = context.coordinator | |
modal.presentationController?.delegate = context.coordinator | |
let top = getTopViewController(from: uiView) | |
top?.present(modal, animated: true) | |
context.coordinator.didPresent = true | |
} | |
} | |
} |
@Amzd Sorry, I didn't realize that my explanation got removed when I updated my code in my comment. What I was trying to do was make it so that when you tap a color, it automatically dismisses but that caused a few other issues with buttons that are displayed on the view behind the Color Picker and so it wasn't worth it for me to try and fix it. I ended up leaving the callback though because 3 less lines of code in my view if it is part of the .colorPickerSheet()
itself instead of using .onChange()
.
Thank you, this is still very helpful! But is there a way to display the picker inside a popover instead of a sheet?
@Amzd thank you for this!
I've noticed that on Catalyst, it first opens up a sheet with just a tiny color selection box in the top left corner. Then pressing the "show colors" button, we get the regular Mac color picker.
@pianostringquartet hmm yea I didnt write this with crossplatform code in mind
@JTostitos Seems you added a callback for selection changes?
You could just use SwiftUIs onChange?
From the top of my head it could be something like this