I tried to make a color picker that has a custom init function to set the original color. And 3 state variable (hue, saturation, brightness) to hold value that will be changed by smaller components. After trying many ways, I still cannot change value of 3 @State variables in custom init function. So weir. Can anyone help me? Thanks
struct ColorPicker: View {
@State var saturation: CGFloat = 0.5
@State var brightness: CGFloat = 0.5
@State var hue: CGFloat = 0.5
@State var alpha: CGFloat = 1
var oriColor : UIColor? = nil
var oriHue: CGFloat = 0
var oriSaturation: CGFloat = 0
var oriBrightness: CGFloat = 0
init(oriColor:UIColor?) {
self.oriColor = oriColor
if let color = oriColor{
color.getHue(&oriHue, saturation: &oriSaturation, brightness: &oriBrightness, alpha: &alpha)
self._hue = State(initialValue:oriHue)
self._saturation = State(initialValue:oriSaturation)
self._brightness = State(initialValue:oriBrightness)
self.hue = oriHue
debugPrint("set value:\(hue)")
}
}
var body: some View {
debugPrint("make view with:\(self.hue)")
let bindingSaturation = Binding<CGFloat>(get: {return self.saturation}, set: {val in self.saturation = val})
let bindingBrightness = Binding<CGFloat>(get: {return self.brightness}, set: {val in self.brightness = val})
let bindingHue = Binding<CGFloat>(get: {return self.hue}, set: {val in self.hue = val})
debugPrint("make view with:\(self.hue)")
return Text("debugging")
}
}
Click here to view code and output
--- UPDATE apply answer from Procrastin8
I changed my code as your suggest
struct ColorPicker: View {
@State var hue: CGFloat
var oriHue: CGFloat = 0.5
var oriSaturation: CGFloat = 0.5
var oriBrightness: CGFloat = 0.5
var oriAlpha: CGFloat = 1
init(oriColor:UIColor?) {
if let color = oriColor {
color.getHue(&oriHue, saturation: &oriSaturation, brightness: &oriBrightness, alpha: &oriAlpha)
self.hue = oriHue
}
else {
self._hue = State(initialValue:oriHue)
}
}
var body: some View {
debugPrint("make view with:\(self.hue)")
return VStack {
BrightnessGrid.init(hue: self.$hue)
}
}
}
struct BrightnessGrid : View {
@Binding var hue: CGFloat
var body: some View {
VStack{
Text("hue:\(self.hue)")
}
}
}
But got "'self' used before all stored properties are initialized" error, as you can see in attach image here
I guest the reason is when we have custom init, then the default initializer will not work then we must manual set the value for @State variable by ourself. Then it's back to the first case.
The init function now is
init(oriColor:UIColor?) {
if let color = oriColor {
color.getHue(&oriHue, saturation: &oriSaturation, brightness: &oriBrightness, alpha: &oriAlpha)
}
self._hue = State(initialValue:oriHue)
}
and still not work.
--- UPDATE 2 I make a new test project and apply the answer of User3441734. When apply in main view it's work perfectly. Then I separated to module it like this.
import SwiftUI
struct ContentView: View {
var colorA: UIColor = UIColor.orange
var colorB: UIColor = UIColor.blue
@State var oriColor: UIColor? = nil
func changeToColorA(){
oriColor = colorA
}
func changeToColorB(){
oriColor = colorB
}
var body: some View {
VStack{
HStack{
Button(action:changeToColorA){
Text("Color A")
}
Button(action:changeToColorB){
Text("Color B")
}
}
TestView(oriColor: oriColor)
}
}
}
struct TestView: View {
@State var hue: CGFloat
var oriHue: CGFloat = 0.5
var oriSaturation: CGFloat = 0.5
var oriBrightness: CGFloat = 0.5
var oriAlpha: CGFloat = 1
init(oriColor:UIColor?) {
if let color = oriColor {
color.getHue(&oriHue, saturation: &oriSaturation, brightness: &oriBrightness, alpha: &oriAlpha)
}
_hue = State(initialValue: oriHue)
}
var body: some View {
debugPrint("make view with:\(self.hue)")
return VStack {
Text("\(hue)").background(Color(hue: Double(hue), saturation: Double(oriSaturation), brightness: Double(oriBrightness), opacity: Double(oriAlpha)))
.onTapGesture {
self.hue = 0.22
}
Slider(value: $hue, in: 0 ... 1) {
Text("HUE")
}
}
}
}
Then nothing happen when clicking on buttons Color A, Color B. Did I do some thing wrong?