【问题标题】:How to update SwiftUI button after event in external class?如何在外部类中的事件后更新 SwiftUI 按钮?
【发布时间】:2021-02-13 10:19:51
【问题描述】:

我想更新按钮,从“暂停”标志,回到“播放”标志;当班级完成演讲任务时。当前代码没有做任何改变...怎么了?

我可以在有条件的情况下做.onChange 吗? (仅当更改是特定的)

struct SwiftUIView: View {
    
    var speaker = Speaker()
    @State var isPlaying = false
        
    var body: some View {

        VStack {
            Button(action: {
                
                if isPlaying {
                    isPlaying.toggle()
                    speaker.synth.pauseSpeaking(at: .immediate)
                } else {
                    isPlaying.toggle()
                    // continue playing here if it was paused before, else ignite speech utterance
                    if speaker.synth.isPaused {
                        speaker.synth.continueSpeaking()
                    } else {
                        speaker.speak("Holly Molly bro")
                    }
                    
                }
            }, label: {
                Text(isPlaying ? "pause" : "play")
            })
            
            
        }
        .onChange(of: speaker.hasStopped, perform: { value in
            isPlaying = false
            print("Who asked for change?")
        })
        
    }
}

...

import AVFoundation
import Combine

class Speaker: ObservableObject, AVSpeechSynthesizerDelegate {
    let synth = AVSpeechSynthesizer()
    
    @Published var hasStopped: Bool = false

    func speak(_ string: String) {
            hasStopped = false
            
            let utterance = AVSpeechUtterance(string: string)
            utterance.voice = AVSpeechSynthesisVoice(language: "en-GB")
            utterance.rate = 0.4
            synth.speak(utterance)
        }
    
    func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
            print("all done")
            
            hasStopped = true
        }
}

【问题讨论】:

  • 为什么不直接检查 hasStopped 而不是使用本地的@State 属性?
  • 我想过这个,但不记得我为什么改变主意了。您是否认为将isPlaying 替换为class?按下按钮时我也会切换状态。

标签: swift swiftui combine


【解决方案1】:

您需要将ObservableObject 属性包装到ObservedObject 包装器中,以便跟踪已发布的属性,例如

struct SwiftUIView: View {
    
    @ObservedObject var speaker = Speaker()     // << here !!
    // @StateObject var speaker = Speaker()     // << if single per view !!

【讨论】:

    【解决方案2】:

    除了Asperi的回答你还需要设置Delegate:

      override init() {
        super.init()
        synth.delegate = self 
      }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-14
      • 1970-01-01
      相关资源
      最近更新 更多