如何在SwiftUI中通过自定义init设置状态值

时间:2020-01-21 08:43:07

标签: state swiftui

我试图制作一个具有自定义init功能的颜色选择器,以设置原始颜色。并具有3个状态变量(色相,饱和度,亮度)以保存将由较小的组件更改的值。在尝试了多种方法之后,我仍然无法在自定义init函数中更改3个@State变量的值。好吧谁能帮我?谢谢

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

---更新应用Procrastin8的答案

我根据您的建议更改了代码

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)")
        }
    }
}

但是在初始化所有存储的属性之前使用了“'self'”错误,如附件图像here

中所示

我来宾,原因是当我们有自定义的init时,默认的初始化程序将不起作用,因此我们必须自行手动设置@State变量的值。然后回到第一种情况。

现在的init函数是

init(oriColor:UIColor?) {

        if let color = oriColor {
            color.getHue(&oriHue, saturation: &oriSaturation, brightness: &oriBrightness, alpha: &oriAlpha)
        }
        self._hue = State(initialValue:oriHue)
    }

仍然无法正常工作。

-更新2 我创建了一个新的测试项目,并应用了User3441734的答案。在主视图中应用时,效果很好。然后,我像这样将其分离成模块。

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")
            }
        }
    }
}

然后单击颜色A,颜色B时没有任何反应。我做错了什么吗?

3 个答案:

答案 0 :(得分:3)

您正在设置默认初始值,然后尝试覆盖State函数中的init容器。尝试同时使用计算值或默认值同时设置它们,但都在init函数中。

struct ColorPicker: View {

    @State var saturation: CGFloat
    @State var brightness: CGFloat
    @State var hue: CGFloat
    @State var alpha: CGFloat

    init(_ color: UIColor?) {
      if let color = color {
          // what you had before
      } else {
          self._saturation = State(initialValue: 0.5)
          // etc.
      }
    }

我也不会完全依赖body函数中的计算值。尝试仅使用一个标签来打印出这些值,然后查看得到的内容,而不是进行调试打印。

注意:您知道@State出售Binding是对projectedValue的权利吗?

SomeView(colorComponent: "hue", binding: $hue)

答案 1 :(得分:0)

要更改国家的初始值,请使用其基础值

import SwiftUI
import PlaygroundSupport

struct ContentView: 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")
            }
        }
    }
}

PlaygroundPage.current.setLiveView(ContentView(oriColor: UIColor.orange))

enter image description here

答案 2 :(得分:0)

尝试了许多方法但未成功。我使用的代码可以正常工作。

import SwiftUI

struct ContentView: View {

    @State var oriColor: UIColor? = nil
    @State var hue: CGFloat = 1
    @State var saturation: CGFloat = 1
    @State var brightness: CGFloat = 1
    @State var alpha: CGFloat = 1

    func setColor(_ oriColor: UIColor){
        self.oriColor = oriColor
        oriColor.getHue(&self.hue, saturation: &self.saturation, brightness: &self.brightness, alpha: &self.alpha)
    }
    func changeToColorA(){
        setColor(UIColor.orange)
    }
    func changeToColorB(){
        setColor(UIColor.blue)
    }
    var body: some View {

         VStack {
            HStack {
                Button(action:changeToColorA) {
                    Text("Color A")
                }

                Button(action:changeToColorB) {
                    Text("Color B")
                }
            }

            ColorPicker(hue: self.$hue, saturation: self.$saturation, brightness: self.$brightness, alpha: self.$alpha)
        }
    }
}

struct ColorPicker: View {

    @Binding var hue: CGFloat
    @Binding var saturation: CGFloat
    @Binding var brightness: CGFloat
    @Binding var alpha: CGFloat

    var body: some View {

         return VStack {
            TestView.init(hue: self.$hue, saturation: self.$saturation, brightness: self.$brightness, alpha:self.$alpha )
        }
    }
}

struct TestView: View {

    @Binding var hue: CGFloat
    @Binding var saturation: CGFloat
    @Binding var brightness: CGFloat
    @Binding var alpha: CGFloat

    var body: some View {

        debugPrint("make view with:\(self.hue)")

        return VStack {
            Text("\(hue)").background(Color(hue: Double(hue), saturation: Double(saturation), brightness: Double(brightness), opacity: Double(alpha)))


            Slider(value: $hue, in: 0 ... 1) {
                Text("HUE")
            }
        }
    }
}