Bharath NS
Bharath NS

Reputation: 43

Computed color does not get updated swiftUI

I am new to SwiftUI and am facing an issue. The variable selectedColor is not getting updated, when I move the slider. My aim is as I move the slider the ColorView Background color should change and appropriate color should be shown as background but color is not getting changed. Any pointers to solve the problem would be helpful. This is how it looks while I expect a capsule with selected color aroun #837c7c.

enter image description here

struct GradientView: View {
    let name: String
    @State private var redValue = 124.0
    @State private var greenValue = 124.0
    @State private var blueValue = 124.0
    @State private var selectedColor: Color = .green
    @State var isEditing = false
    var body: some View {
        VStack(spacing: 0) {
            VStack {
                HStack {
                    VStack {
                        Slider(value: $redValue,
                               in: 0...255,
                               step: 1
                        ).onChange(of: self.redValue, perform: { newValue in
                            self.sliderChanged()
                        })
                        .accentColor(.red)
                        Slider(value: $greenValue,
                               in: 0...255,
                               step: 1
                        ).onChange(of: self.greenValue, perform: { newValue in
                            self.sliderChanged()
                        })
                        .accentColor(.green)
                        
                        Slider(value: $blueValue,
                               in: 0...255,
                               step: 1
                        ).onChange(of: self.blueValue, perform: { newValue in
                            self.sliderChanged()
                        }).accentColor(.blue)
                    }

                    VStack {
                        ColorView(selectedColor: $selectedColor)
                            .padding()
                            //.foregroundColor(.black)
                    }
                    //.background(selectedColor)//.background(Capsule().fill(selectedColor))
                        //.init(red: redValue, green: greenValue, blue: blueValue)
                }
            }
        }
        .padding()
        .frame(maxHeight: .infinity, alignment: .top)
        .navigationTitle(name)
    }
    
    func sliderChanged() {
        selectedColor = Color.init(red: redValue, green: greenValue, blue: blueValue)
        print("Slider value changed to ")
        print("\(redValue):\(greenValue):\(blueValue)")
    }
}


struct ColorView: View {
    @Binding var selectedColor: Color
    
  var body: some View {

      let components = selectedColor.cgColor?.components
      Text("#\(String(format:"%02X", Int(components?[0] ?? 0)))\(String(format:"%02X", Int(components?[1] ?? 0)))\(String(format:"%02X", Int(components?[2] ?? 0)))")
          .background(Capsule().fill(selectedColor))
          .padding()
          .font(.system(.caption).bold())
  }
}

Upvotes: 2

Views: 219

Answers (1)

Asperi
Asperi

Reputation: 257749

The Color constructor with components requires colour in 0...1, so we just need to convert slider value to needed range:

selectedColor = Color.init(red: CGFloat(redValue)/255, 
                         green: CGFloat(greenValue/255), 
                         blue: CGFloat(blueValue)/255)

Tested with Xcode 14 / iOS 16

Update: however instead I recommend to change selectedColor to CGColor type, because SwiftUI.Color.cgColor can return nil (as documented)

demo

so more appropriate solution would be:

    @State private var selectedColor: CGColor = UIColor.green.cgColor // << any default !!

    // ...

    func sliderChanged() {
        selectedColor = CGColor.init(red: CGFloat(redValue)/255, green: CGFloat(greenValue/255), blue: CGFloat(blueValue)/255, alpha: 1.0)
        print("Slider value changed to ")
        print("\(redValue):\(greenValue):\(blueValue)")
    }
}


struct ColorView: View {
    @Binding var selectedColor: CGColor
    
  var body: some View {

      let components: [CGFloat] = selectedColor.components ?? [0, 0, 0]
      Text("#\(String(format:"%02X", Int(components[0]*255)))\(String(format:"%02X", Int(components[1]*255)))\(String(format:"%02X", Int(components[2]*255)))")
          .padding()
          .background(Capsule().fill(Color(selectedColor)))
          .font(.system(.caption).bold())
  }
}

Upvotes: 1

Related Questions