Как установить значение состояния из пользовательского init в SwiftUI - PullRequest
0 голосов
/ 21 января 2020

Я попытался создать палитру цветов, в которой есть пользовательская функция инициализации для установки исходного цвета. И 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» до инициализации всех сохраненных свойств, как вы можете видеть на прикрепленном изображении здесь

Я гость, причина в том, что когда у нас есть пользовательский init, то инициализатор по умолчанию не будет работать, тогда мы должны вручную установить значение для переменной @State самостоятельно. Затем вернемся к первому случаю.

Функция инициализации теперь

init(oriColor:UIColor?) {

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

и все еще не работает.

--- ОБНОВЛЕНИЕ 2 Я создаю новый тестовый проект и применяю ответ пользователя 3441734. При применении в основном виде это работает отлично. Затем я разделил его на модуль следующим образом.

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 голосов
/ 21 января 2020

Вы устанавливаете начальные значения по умолчанию, а затем пытаетесь перезаписать контейнер 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)
0 голосов
/ 27 января 2020

После многих попыток, но не успеха. Я использую этот код, который может работать.

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")
            }
        }
    }
}
0 голосов
/ 21 января 2020

для изменения начального значения 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))

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...