I assign a sound to a scene in Reality Composer as in the image below
I would like to create an UIButton that can be pressed to stop the sound. Can I do that?
CodePudding user response:
I created three Reality Composer actions for box scene: they are Play Sound
, Spin
and
SwiftUI
My code is as simple as that. Primary stop()
methods are for immediate stop of audio and animation. Secondary stop()
methods are the content of completion handler for onAction
property.
import SwiftUI
import RealityKit
struct ContentView : View {
@State var completion: ((Entity?) -> ()) = { _ in }
@State var arView = ARView(frame: .zero)
@State var boxScene = try! Experience.loadBox()
var body: some View {
ZStack {
ARViewContainer(arView: $arView, boxScene: $boxScene)
.ignoresSafeArea()
VStack {
Button("Stop") {
boxScene.steelBox?.stopAllAudio() // 1
boxScene.steelBox?.stopAllAnimations() // 1
print("Actions are stopped.")
completion = {
$0?.stopAllAudio() // 2
$0?.stopAllAnimations() // 2
$0?.scale = [1,15,1]
print("Both actions were completely stopped.")
}
boxScene.actions.occured.onAction = completion
}
Spacer()
}
}
}
}
And here's an ordinary binding.
struct ARViewContainer : UIViewRepresentable {
@Binding var arView: ARView
@Binding var boxScene: Experience.Box
func makeUIView(context: Context) -> ARView {
arView.scene.anchors.append(boxScene)
return arView
}
func updateUIView(_ view: ARView, context: Context) { }
}
Note that Notify
action is the last one in the sequence. After what time the secondary stop()
methods will be applied (I mean the content of the completion handler), depends on the duration of the audio file or animation (my audio's duration is 14 sec).
UIKit
UIKit solution is somehow different and slightly simpler.
import UIKit
import RealityKit
class ViewController : UIViewController {
@IBOutlet var arView: ARView!
let boxScene = try! Experience.loadBox()
var completion: ((Entity?) -> Void)? = { _ in }
override func viewDidLoad() {
super.viewDidLoad()
let rect = CGRect(x: 50, y: 50, width: 100, height: 50)
let stopButton = UIButton(frame: rect)
stopButton.setTitle("Stop", for: .normal)
stopButton.addTarget(self,
action: #selector(stopPlayingAudioAndAnime),
for: .touchUpInside)
arView.addSubview(stopButton)
arView.scene.anchors.append(boxScene)
}
@objc private func stopPlayingAudioAndAnime() {
boxScene.steelBox?.stopAllAudio() // 1
boxScene.steelBox?.stopAllAnimations() // 1
completion = { entity in
entity?.stopAllAudio() // 2
entity?.stopAllAnimations() // 2
print("Completely Stopped")
}
boxScene.actions.occured.onAction = completion
}
}
P. S.
However, if you'll be using Play Music
action (in other words, on the scene basis, not on the object basis, like Play Sound
action), you can implement your idea this way:
arView.scene.anchors[0].children[0].stopAllAudio()
completion = { entity in
entity?.scene?.anchors[0].children[0].stopAllAudio()
}