Last active
September 13, 2024 22:02
-
-
Save mobibob/80ae91e66b53384829ef3bf5b54586b4 to your computer and use it in GitHub Desktop.
SwiftUI Color Extension - contrasting for text on background
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extension Color { | |
static var forExampleMyDarkRed: Color { | |
return Color(hue: 1.0, saturation: 1.0, brightness: 0.6, opacity: 0.8) | |
} | |
init(hex: String) { | |
let scanner = Scanner(string: hex) | |
_ = scanner.scanString("#") // Skip the '#' prefix if present | |
var rgb: UInt64 = 0 | |
scanner.scanHexInt64(&rgb) | |
let r = Double((rgb & 0xFF0000) >> 16) / 255.0 | |
let g = Double((rgb & 0x00FF00) >> 8) / 255.0 | |
let b = Double(rgb & 0x0000FF) / 255.0 | |
self.init(red: r, green: g, blue: b, opacity: 1.0) | |
} | |
func toHex2() -> String { | |
return self.description | |
} | |
func isLight() -> Bool { | |
let components = self.cgColor?.components | |
let h = (components?[0] ?? 0) * 299 | |
let v = (components?[1] ?? 0) * 587 | |
let b = components?[2] ?? 0 | |
let brightness = (h + v + (b) * 114) / 1000 | |
return brightness > 0.5 | |
} | |
func contrastingColor() -> Color { | |
return self.isLight() ? .black : .white | |
} | |
static let customPurple = Color(red: 128/255, green: 0/255, blue: 128/255) | |
static let customTeal = Color(red: 0/255, green: 128/255, blue: 128/255) | |
static var tone0: Color { Color(hex: "000000") } | |
static var tone10: Color { Color(hex: "1A1A1A") } | |
static var tone20: Color { Color(hex: "333333") } | |
static var tone30: Color { Color(hex: "4D4D4D") } | |
static var tone40: Color { Color(hex: "676767") } | |
static var tone50: Color { Color(hex: "808080") } | |
static var tone60: Color { Color(hex: "999999") } | |
static var tone70: Color { Color(hex: "B3B3B3") } | |
static var tone80: Color { Color(hex: "CCCCCC") } | |
static var tone90: Color { Color(hex: "E6E6E6") } | |
static var tone95: Color { Color(hex: "F2F2F2") } | |
static var tone99: Color { Color(hex: "FAFAFA") } | |
static var tone100: Color { Color(hex: "FFFFFF") } | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
struct TonalPalette: Identifiable { | |
let id = UUID() | |
let name: String | |
let colors: [TonalColor] | |
} | |
// make this conform to hashable | |
final class TonalColor: Hashable { | |
var id: UUID | |
var tonalColor: Color | |
init(id: UUID = UUID() ,tonalColor: Color) { | |
self.id = id | |
self.tonalColor = tonalColor | |
} | |
static func == (lhs: TonalColor, rhs: TonalColor) -> Bool { | |
lhs.id == rhs.id | |
} | |
func hash(into hasher: inout Hasher) { | |
hasher.combine(id) | |
} | |
} | |
// MARK: - ViewModel | |
class PaletteChoices: ObservableObject { | |
static let shared = PaletteChoices() | |
@Published var palettes: [TonalPalette] = [] | |
private init() { | |
loadPalettes() | |
} | |
private func loadPalettes() { | |
palettes = [ | |
TonalPalette(name: "Purple", colors: [ | |
TonalColor(tonalColor: Color.tone0), | |
TonalColor(tonalColor: Color.tone10), | |
TonalColor(tonalColor: Color.tone20), | |
TonalColor(tonalColor: Color.tone30), | |
TonalColor(tonalColor: Color.tone40), | |
TonalColor(tonalColor: .yellow.opacity(0.5)), | |
TonalColor(tonalColor: Color.tone50), | |
TonalColor(tonalColor: Color.tone60), | |
TonalColor(tonalColor: Color.tone70.opacity(0.9)), | |
TonalColor(tonalColor: Color.tone80), | |
TonalColor(tonalColor: .purple.opacity(0.5)), | |
TonalColor(tonalColor: Color.tone95), | |
TonalColor(tonalColor: Color.tone99), | |
TonalColor(tonalColor: Color.tone100), | |
]), | |
TonalPalette(name: "Teal", colors: [ | |
TonalColor(tonalColor: .teal.opacity(0.1)), | |
TonalColor(tonalColor: Color.tone10), | |
TonalColor(tonalColor: .teal.opacity(0.2)), | |
TonalColor(tonalColor: .teal.opacity(0.3)), | |
TonalColor(tonalColor: .teal.opacity(0.4)), | |
TonalColor(tonalColor: .teal.opacity(0.5)), | |
TonalColor(tonalColor: .teal.opacity(0.6)), | |
TonalColor(tonalColor: .teal.opacity(0.7)), | |
TonalColor(tonalColor: .teal.opacity(0.8)), | |
TonalColor(tonalColor: .teal.opacity(0.9)), | |
TonalColor(tonalColor: .teal) | |
]), | |
// Add more palettes here... | |
] | |
} | |
} | |
#Preview("Palette") { | |
VStack() { | |
HStack(alignment: .center) { | |
ContentView() | |
.frame(width: 320, height: 280) | |
} | |
} | |
} | |
struct ContentView: View { | |
@StateObject private var paletteChoices = PaletteChoices.shared | |
var body: some View { | |
List { | |
ForEach(paletteChoices.palettes) { palette in | |
Section(header: Text(palette.name) | |
.foregroundColor(Color.accentColor) | |
.font(.title2)) { | |
ForEach(palette.colors, id: \.self) { color in | |
Text("\(color.tonalColor.toHex2())") | |
.font(.caption) | |
.containerShape(Rectangle()) | |
.frame(width: 90, height: 30) | |
.background(color.tonalColor) | |
.foregroundColor(color.tonalColor.contrastingColor()) | |
} | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment