如何在外部类中的事件后更新 SwiftUI 按钮?

Posted

技术标签:

【中文标题】如何在外部类中的事件后更新 SwiftUI 按钮?【英文标题】:How to update SwiftUI button after event in external class? 【发布时间】: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?按下按钮时我也会切换状态。 【参考方案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 
  

【讨论】:

以上是关于如何在外部类中的事件后更新 SwiftUI 按钮?的主要内容,如果未能解决你的问题,请参考以下文章

如何在外部类上加载@ConfigurationProperties?

内部类中的私有构造函数在外部类中初始化

在外部类中使用类模板时如何定义内部类构造函数?

更新列表中的一行 (SwiftUI)

从按钮单击事件直接调用存储在外部 JS 文件中的 JavaScript 函数

更新单独结构中的@AppStorage 后如何更新 SwiftUI 视图