SwiftUI call function on variable change

谁说我不能喝 提交于 2020-05-05 14:32:02

问题


I am trying to convert a view of my watchOS App to Swift UI. I wanted to port the volume control that can be found in watchKit to SwiftUI with custom controls. In the image below you can see the current state of the view.

The volume control changes the progress of the ring according to current state volume and the volume also changes when I turn the Digital Crown. Without SwiftUI it was possible to call a function on the turn of the crown. This has changed and the system only allows me to bind a variable to it.

What I want to do know is to bind a variable and call a function on every change of that variable. Because the normal Digital Crown behavior does not fulfill my needs.

One thing that works, but is far from perfect is:

.digitalCrownRotation($crownAccumulator, from: -100.0, through: 100.0, by: 1, sensitivity: .low, isContinuous: true, isHapticFeedbackEnabled: true)
.onReceive(Just(self.crownAccumulator), perform: self.crownChanged(crownAccumulator:))

OnReceive will be called with every twist of the crown, but it will also be called with every other update to the view.

So what I want is a pipeline like this:

Crown rotates → crownAccumulator changes → Function called async → Function updates volume

In the past I would have done this with a didSet, but this is no longer available

Here the code of it:


    @ObservedObject var group: Group
    @State var animateSongTitle: Bool = false

    @State var songTitle: String = "Very long song title that should be scrolled"
    @State var artist: String = "Artist name"


    @State var volume: Int = 30
    @State var isMuted = false
    @State var crownAccumulator: CGFloat = 0.0


    var body: some View {

       VStack(alignment: .center) {
            TitleView(songTitle: $songTitle, artist: $artist)
            GroupControlButtons(
                skipPreviousAction: skipPrevious,
                skipNextAction: skipNext,
                playPauseAction: playPause,
                group: group)

            ZStack {
                HStack {
                    VolumeControl(
                        volumeLevel: $volume,
                        isMuted: $isMuted,
                        muteAction: self.muteButtonPressed)
                            .frame(minWidth: 40.0, idealWidth: 55, minHeight: 40.0, idealHeight: 55, alignment: .center)
                            .aspectRatio(1.0, contentMode: .fit)


                }
            }


        }
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
        .edgesIgnoringSafeArea([.bottom])
        .focusable(true)
//        .digitalCrownRotation($crownAccumulator)
        .digitalCrownRotation($crownAccumulator, from: -100.0, through: 100.0, by: 1, sensitivity: .low, isContinuous: true, isHapticFeedbackEnabled: true)
        .onReceive(Just(self.crownAccumulator), perform: self.crownChanged(crownAccumulator:))


Here's the current view:


回答1:


You can use a custom Binding, that calls some code in set. For example from :

extension Binding {
    /// Execute block when value is changed.
    ///
    /// Example:
    ///
    ///     Slider(value: $amount.didSet { print($0) }, in: 0...10)
    func didSet(execute: @escaping (Value) ->Void) -> Binding {
        return Binding(
            get: {
                return self.wrappedValue
            },
            set: {
                execute($0)
                self.wrappedValue = $0
            }
        )
    }
}



回答2:


As you said "In the past I would have done this with a didSet, but this is no longer available" I test below code it works perfectly

struct pHome: View {
 @State var prog:Int = 2 {
    willSet{
        print("willSet: newValue =\(newValue)  oldValue =\(prog)") 
    }
    didSet{
        print("didSet: oldValue=\(oldValue) newValue=\(prog)")
        //Write code, function do what ever you want todo 
    }
} 
 var body: some View {
VStack{
                Button("Update"){
                    self.prog += 1
                }
                Text("\(self.prog)%")
  }
 }
}


来源:https://stackoverflow.com/questions/59379132/swiftui-call-function-on-variable-change

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!