In this blog, I will use SwiftUI with concept of state
and binding
to pass values.
// ColorParser.swift
import Foundation
// get hex code, return rgb value
func getRGBAColor(rgba: String) -> (UInt8,UInt8,UInt8,UInt8) {
var red: UInt8 = 0
var green: UInt8 = 0
var blue: UInt8 = 0
var alpha: UInt8 = 255
var hexColor = rgba //String(rgba[rgba.startIndex...])
// 3 or 4 characters are treated as 3 and 4 digit CSS color values
if hexColor.count == 3 || hexColor.count == 4 {
var colorCharacterArray = Array(hexColor)
colorCharacterArray.insert(colorCharacterArray[0], at: 1)
colorCharacterArray.insert(colorCharacterArray[2], at: 3)
colorCharacterArray.insert(colorCharacterArray[4], at: 5)
if colorCharacterArray.count == 7 { // if we started with a 4 digit CSS hex color
colorCharacterArray.insert(colorCharacterArray[6], at: 7 )
}
print(colorCharacterArray)
hexColor = String(colorCharacterArray)
}
let scanner = Scanner(string: hexColor)
var hexNumber: UInt64 = 0
// 8 characters are treated as 8 digit RRGGBBAA values
if hexColor.count == 8 {
if scanner.scanHexInt64(&hexNumber) {
red = UInt8((hexNumber & 0xff000000) >> 24)
green = UInt8((hexNumber & 0x00ff0000) >> 16)
blue = UInt8((hexNumber & 0x0000ff00) >> 8)
alpha = UInt8(hexNumber & 0x000000ff)
}
// 6 characters are treated as 6 digit RRGGBB values
} else if hexColor.count == 6 { // assume no alpha value
if scanner.scanHexInt64(&hexNumber) {
red = UInt8((hexNumber & 0xff0000) >> 16)
green = UInt8((hexNumber & 0x00ff00) >> 8)
blue = UInt8((hexNumber & 0x0000ff))
alpha = 255 // set to max
}
}
return (red,green,blue,alpha)
}
// ColorModel.swift
import Foundation
struct ColorModel {
var red: Double
var green: Double
var blue: Double
var alpha: Double
// computational property
var hex: String {
get {
// 02 = minimum 2 characters
String(format: "%02X%02X%02X%02X", Int(red), Int(green), Int(blue), Int(alpha))
}
set {
// newValue = result from get
let rgba = getRGBAColor(rgba: newValue) // retruns tuple (red, green, blue, alpha)
self.red = Double(rgba.0)
self.green = Double(rgba.1)
self.blue = Double(rgba.2)
self.alpha = Double(rgba.3)
}
}
}
Create multiple Views
// TextView
import SwiftUI
struct TextView: View {
@Binding var hex: String
var applyActions: () -> Void
var body: some View {
HStack {
TextField("Enter Hex Color", text: $hex)
Button(action: applyActions) {
Text("Apply")
}
}
}
}
// ColorPreviewView
import SwiftUI
struct ColorPreviewView: View {
@Binding var red: Double
@Binding var green: Double
@Binding var blue: Double
@Binding var alpha: Double
var hex: String {
String(format: "%02X%02X%02X%02X", Int(red), Int(green), Int(blue), Int(alpha))
}
var body: some View {
VStack {
Rectangle()
// look out $ sign is missing why?
// we need it for binding. when do we need to bind? we bind two when you want to pass something
// are we passing something in here? we don't need to use $ here
.fill(Color(red: red/255.0, green: green/255.0, blue: blue/255.0, opacity: alpha/255.0))
Text("Hex: \(hex)")
}
}
}
// ColorSliderView
import SwiftUI
struct ColorSliderView: View {
@Binding var value: Double // holds binding variable (props in react) -> pass the binding to parent view (SliderView)
var colorName: String
var sliderColor: Color {
switch colorName {
case "Red":
return Color.red
case "Green":
return Color.green
case "Blue":
return Color.blue
case "Alpha":
return Color.black
default:
return Color.primary
}
}
var body: some View {
VStack {
// provide value with $
// slider can update the value as well
// bind state to the slider(UI) -> slider will update value whenever you ask to change it
Slider(value: $value, in: 0...255, step: 1)
// apply color to the slider
.accentColor(sliderColor)
HStack {
Text("\(colorName):")
Text(String(format: "%.0f", value))
}
.foregroundColor(sliderColor)
}
}
}
// SliderView.swift
import SwiftUI
// to provide four sliders in the view
// building a parent view of ColorSliderView
struct SliderVIew: View {
@Binding var red: Double
@Binding var green: Double
@Binding var blue: Double
@Binding var alpha: Double
var body: some View {
VStack {
ColorSliderView(value: $red, colorName: "Red")
ColorSliderView(value: $green, colorName: "Green")
ColorSliderView(value: $blue, colorName: "Blue")
ColorSliderView(value: $alpha, colorName: "Alpha")
}
}
}
Combine all views we created in ContentView
// ContentView
import SwiftUI
struct ContentView: View {
// initial state
@State private var red: Double = 127.5
@State private var green: Double = 127.5
@State private var blue: Double = 127.5
@State private var alpha: Double = 255.0
@State private var hex: String = "7F7F7FFF"
var body: some View {
// now we have to combine all the views to main in ContentView
VStack {
TextView(hex: $hex, applyActions: applyHex)
// binding: bingding variable changes -> view changes automatically
ColorPreviewView(red: $red, green: $green, blue: $blue, alpha: $alpha)
SliderVIew(red: $red, green: $green, blue: $blue, alpha: $alpha)
Button(action: resetValue) {
Text("Reset")
}
.padding()
}
.padding()
}
// method for applyActions for Stack above
private func applyHex() {
let rgba = getRGBAColor(rgba: hex)
red = Double(rgba.0)
green = Double(rgba.1)
blue = Double(rgba.2)
alpha = Double(rgba.3)
}
private func resetValue() {
red = 127.5
green = 127.5
blue = 127.5
alpha = 127.5
hex = "7F7F7FFF"
}
}
Demo
When 'reset' button is clicked, it goes back to the initial state.
Top comments (0)