【问题标题】:How to set state value from custom init in SwiftUI如何在 SwiftUI 中从自定义初始化设置状态值
【发布时间】:2020-05-07 06:43:06
【问题描述】:

我尝试制作一个具有自定义初始化功能的颜色选择器来设置原始颜色。以及 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")
    }
}

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' used”错误,如附件图片here中所示

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

【问题讨论】:

  • 如果您在此处复制可重现和可复制的代码,而不是泄露 BrightnessGrid 和 HueSlider 的代码,这对我们想要提供帮助的人来说会容易得多。或者以这种方式更改/简化您的代码,如果您不想在这里显示您的代码,我们可以复制并运行它...

标签: state swiftui


【解决方案1】:

您正在设置默认初始值,然后尝试覆盖 init 函数中的 State 容器。尝试使用您的计算值或默认值同时设置它们,但都在 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 函数中的计算值。尝试只使用一个打印出这些值的标签,然后看看你得到了什么,而不是你的调试打印。

注意:您知道@StateBinding 作为其projectedValue,对吗?

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

【讨论】:

  • 感谢您的帮助。我已经应用了您的解决方案,但仍然没有运气。您可以在更新的部分中看到。我希望我不会误会你的想法。
  • 您的屏幕截图显示了完全不同的内容。您从实例变量声明中删除了 @State,但您仍在设置默认值。
  • 你看原帖头的截图了吗?我按照您在第二部分中的建议更新了新应用,并带有 UPDATE 标签。我只是使用了 1 个名为 hue 的状态变量,如果我们不为这个状态变量设置值,编译器会报错。
  • 是的,我看到了。就像我说的,你在 init 函数中做了两件完全不同的事情。 self.hueself._hue 不同。一种是设置 wrapped 值,另一种是设置整个 State 变量。
【解决方案2】:

改变State的初始值使用它的基础值

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

【讨论】:

  • 谢谢你,但我和你的完全一样。
  • 那么什么不起作用?这样 txt1 的初始值会按照您的要求从 init 更改。
  • 我已经创建了新项目并测试了您的代码并且它有效。也许问题出在 init 函数之外的其他地方,因为我在你的使用完全相同。谢谢。
  • @user13441734 。你的代码运行良好。为了更方便,我拆分为像 UPDATE 2 这样的单独模块,但它没有按预期工作。可以看看吗?
【解决方案3】:

尝试了很多方法但没有成功。我使用这个可以工作的代码。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-30
    • 2018-08-22
    • 2019-10-30
    • 2016-10-15
    • 2012-06-26
    • 1970-01-01
    • 2021-04-18
    • 1970-01-01
    相关资源
    最近更新 更多