首页 > 解决方案 > 如何在 SwiftUI 中从自定义初始化设置状态值

问题描述

我试图制作一个具有自定义初始化功能的颜色选择器来设置原始颜色。以及 3 个状态变量(色调、饱和度、亮度)来保存将由较小组件更改的值。在尝试了很多方法之后,我仍然无法在自定义初始化函数中更改 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")
    }
}

单击此处查看代码和输出

--- 更新应用 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' used”错误,如您在此处的附加图片中所见

我来宾的原因是当我们有自定义初始化时,默认初始化程序将不起作用,那么我们必须手动设置 @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 按钮时什么也没有发生。我做错了什么吗?

标签: stateswiftui

解决方案


您正在设置默认初始值,然后尝试覆盖函数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函数内部的计算值。尝试只使用一个打印出这些值的标签,然后看看你得到了什么,而不是你的调试打印。

注意:你知道@Statevends aBinding是对的projectedValue吗?

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

推荐阅读