Skip to content

Instantly share code, notes, and snippets.

@daniloc
Last active April 21, 2023 09:48
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save daniloc/b31612b315dc05f73e8d77e271196b5e to your computer and use it in GitHub Desktop.
Save daniloc/b31612b315dc05f73e8d77e271196b5e to your computer and use it in GitHub Desktop.
A simple color picker with enum for easy storage
struct ColorPicker: View {
enum Option: Int, CaseIterable {
case none,
red,
orange,
yellow,
green,
teal,
blue,
purple
func color() -> Color {
switch self {
case .none:
return Color.primary
case .red:
return Color.red
case .orange:
return Color.orange
case .yellow:
return Color.yellow
case .green:
return Color.green
case .blue:
return Color.blue
case .purple:
return Color(.systemIndigo)
case .teal:
return Color(.systemTeal)
}
}
}
@Binding var selection: Option
//MARK: - Style Details
var background: some View {
RoundedRectangle(cornerRadius: 25)
.fill(Color(.systemGray5))
}
func backgroundForOption(_ option: Option) -> Color {
if option == selection {
return Color(.systemBackground)
} else {
return .clear
}
}
func sizeForOption(_ option: Option) -> CGFloat {
if option == selection {
return 22.0
} else {
return 18.0
}
}
let selectionRingWidth: CGFloat = 40.0
let containerHeight: CGFloat = 50.0
func imageNameForOption(_ option: Option) -> String {
if option != selection {
return "circle.fill"
} else {
return "smallcircle.fill.circle.fill"
}
}
//MARK: - Views
func imageForOption(_ option: Option) -> some View {
Image(systemName: self.imageNameForOption(option))
.onTapGesture {
self.selection = option
}
.font(.system(size: self.sizeForOption(option)))
.foregroundColor(option.color())
.frame(width: self.selectionRingWidth, height: self.selectionRingWidth, alignment: .center)
.cornerRadius(containerHeight / 2)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
var body: some View {
ZStack(alignment: .ZAlignment) {
Circle()
.fill(Color(.systemBackground))
.frame(width: self.selectionRingWidth, height: self.selectionRingWidth, alignment: .center)
.alignmentGuide(HorizontalAlignment(Alignment.CustomAlignment.self), computeValue: { d in d[HorizontalAlignment.center] })
.animation(.spring())
HStack {
ForEach(Option.allCases, id: \.self) { option in
Group {
if option == self.selection {
self.imageForOption(option)
.alignmentGuide(HorizontalAlignment(Alignment.CustomAlignment.self), computeValue: { d in d[HorizontalAlignment.center] })
} else {
self.imageForOption(option)
}
}
}
}
}
.padding(4)
.frame(maxWidth: .infinity, minHeight: self.containerHeight, maxHeight: self.containerHeight, alignment: .center)
.background(background)
}
}
extension Alignment {
//adapted from: https://swiftui-lab.com/alignment-guides/
enum CustomAlignment : AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat {
return d[.bottom]
}
}
static let ZAlignment = Alignment(horizontal: HorizontalAlignment(CustomAlignment.self), vertical: .center)
}
struct ColorPicker_Previews: PreviewProvider {
//via: https://stackoverflow.com/a/59626213/150181
static var previews: some View {
PreviewWrapper()
}
struct PreviewWrapper: View {
@State(initialValue: .none) var option: ColorPicker.Option
var body: some View {
ColorPicker(selection: $option)
}
}
}
@daniloc
Copy link
Author

daniloc commented Mar 27, 2020

Simple SwiftUI color picker with dark mode support. Uses an enum to make selection storage in Core Data, etc, easy.

Screen Shot 2020-03-27 at 10 29 57 AM

Usage:

ColorPicker(selection: $selectedColorOption)
[]
let color = selectedColorOption.color()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment