swiftUI:AVAudioPlayer 的奇怪行为
swiftUI: strange behavior with AVAudioPlayer
我想为一个特别为盲人设计的应用程序构建一个引导屏幕。所以页面应该播放一个小的 mp3 文件。
但是,如果我实现附件中的代码,这种行为对我来说似乎很奇怪。
如果我从第 1 页更改为第 2 页,第一个 mp3 文件停止,第二个开始。如我所愿。
如果我进一步转到第 3 页,第 2 页的 mp3 将继续,第 3 页的 mp3 也会开始。两种声音相互叠加。
不明白为什么.onDisappear有时候好像没有被执行...
有时 Xcode 抛出一个
线程 1:致命错误:在隐式展开可选值时意外发现 nil
--> 根据 jnpdx 的提示解决了 - 谢谢
在 .onDisappear 部分。
这是我的问题的一个小视频。看到视频可能更容易理解我的意思...
https://www.eckeonline.de/RPReplay_Final1643832563.MP4
import SwiftUI
import AVKit
struct ManualView: View {
let titleText = ["Willkommen", "Kategorien", "Neuigkeiten","Beispiel", "star.fill","cart", "star.fill","cart", "star.fill"]
let titleImage = ["character.book.closed.fill", "list.dash", "megaphone.fill","moon.zzz.fill", "star.fill","cart", "star.fill","cart", "star.fill"]
let soundFile = ["WelcomePage","CategoryPage", "NewsPage", "ExamplePage","WelcomePage", "WelcomePage", "WelcomePage","WelcomePage", "WelcomePage", "WelcomePage"]
var body: some View {
TabView {
ForEach(0..<4) { value in
OnboardingPage(soundFile: soundFile[value], title: titleText[value] , image: titleImage[value])
.tag(value)
}
}
.tabViewStyle(.page(indexDisplayMode: .always))
}
}
struct OnboardingPage: View {
var soundFile: String
let title: String
let image: String
@State var audioPlayer: AVAudioPlayer!
var body: some View {
VStack(spacing: 25) {
// PlayMP3View(soundFile: soundFile)
Text(title)
.padding(.horizontal, 20)
.font(.system(size: 200))
.lineLimit(1)
.minimumScaleFactor(0.25)
// .font(.largeTitle)
.foregroundColor(.primary)
.accessibility(hidden: true)
Spacer()
Image(systemName: image)
.font(.system(size: 200))
.foregroundColor(.primary)
.accessibility(hidden: true)
Spacer()
}
.onAppear() {
if let sound = Bundle.main.path(forResource: soundFile, ofType: "mp3") {
self.audioPlayer = try! AVAudioPlayer(contentsOf: URL(fileURLWithPath: sound))
self.audioPlayer.play()
}
}
.onDisappear() {
self.audioPlayer.pause()
}
}
}
任何时候你使用 !,如果该值最终为零,你就有崩溃的风险。这里最简单的解决方案是使 audioPlayer 成为可选的。
其次,关于重叠音频的问题,标签可能没有真正卸载(也没有调用 onDisappear
)。除了使用 onAppear
和 onDisappear
,您还可以使用 onChange
并观察 TabView
的选择(为简洁起见,删除了一些 AudioPlayer
代码):
struct ManualView: View {
let titleText = ["Willkommen", "Kategorien", "Neuigkeiten","Beispiel", "star.fill","cart", "star.fill","cart", "star.fill"]
let titleImage = ["character.book.closed.fill", "list.dash", "megaphone.fill","moon.zzz.fill", "star.fill","cart", "star.fill","cart", "star.fill"]
let soundFile = ["WelcomePage","CategoryPage", "NewsPage", "ExamplePage","WelcomePage", "WelcomePage", "WelcomePage","WelcomePage", "WelcomePage", "WelcomePage"]
@State private var selection = -1
var body: some View {
TabView(selection: $selection) {
ForEach(0..<4) { value in
OnboardingPage(soundFile: soundFile[value],
title: titleText[value],
image: titleImage[value],
isActive: selection == value)
.tag(value)
}
}
.tabViewStyle(.page(indexDisplayMode: .always))
.onAppear {
selection = 0 //trick to get onChange triggered on first screen
}
}
}
struct OnboardingPage: View {
var soundFile: String
let title: String
let image: String
var isActive : Bool
@State var audioPlayer: AVAudioPlayer?
var body: some View {
VStack(spacing: 25) {
Text(title)
}
.onChange(of: isActive) { newValue in
if newValue {
print("Play \(title)")
audioPlayer?.play()
} else {
print("Stop \(title)")
audioPlayer?.stop()
}
}
}
}
我想为一个特别为盲人设计的应用程序构建一个引导屏幕。所以页面应该播放一个小的 mp3 文件。
但是,如果我实现附件中的代码,这种行为对我来说似乎很奇怪。 如果我从第 1 页更改为第 2 页,第一个 mp3 文件停止,第二个开始。如我所愿。 如果我进一步转到第 3 页,第 2 页的 mp3 将继续,第 3 页的 mp3 也会开始。两种声音相互叠加。
不明白为什么.onDisappear有时候好像没有被执行...
有时 Xcode 抛出一个 线程 1:致命错误:在隐式展开可选值时意外发现 nil --> 根据 jnpdx 的提示解决了 - 谢谢
在 .onDisappear 部分。
这是我的问题的一个小视频。看到视频可能更容易理解我的意思...
https://www.eckeonline.de/RPReplay_Final1643832563.MP4
import SwiftUI
import AVKit
struct ManualView: View {
let titleText = ["Willkommen", "Kategorien", "Neuigkeiten","Beispiel", "star.fill","cart", "star.fill","cart", "star.fill"]
let titleImage = ["character.book.closed.fill", "list.dash", "megaphone.fill","moon.zzz.fill", "star.fill","cart", "star.fill","cart", "star.fill"]
let soundFile = ["WelcomePage","CategoryPage", "NewsPage", "ExamplePage","WelcomePage", "WelcomePage", "WelcomePage","WelcomePage", "WelcomePage", "WelcomePage"]
var body: some View {
TabView {
ForEach(0..<4) { value in
OnboardingPage(soundFile: soundFile[value], title: titleText[value] , image: titleImage[value])
.tag(value)
}
}
.tabViewStyle(.page(indexDisplayMode: .always))
}
}
struct OnboardingPage: View {
var soundFile: String
let title: String
let image: String
@State var audioPlayer: AVAudioPlayer!
var body: some View {
VStack(spacing: 25) {
// PlayMP3View(soundFile: soundFile)
Text(title)
.padding(.horizontal, 20)
.font(.system(size: 200))
.lineLimit(1)
.minimumScaleFactor(0.25)
// .font(.largeTitle)
.foregroundColor(.primary)
.accessibility(hidden: true)
Spacer()
Image(systemName: image)
.font(.system(size: 200))
.foregroundColor(.primary)
.accessibility(hidden: true)
Spacer()
}
.onAppear() {
if let sound = Bundle.main.path(forResource: soundFile, ofType: "mp3") {
self.audioPlayer = try! AVAudioPlayer(contentsOf: URL(fileURLWithPath: sound))
self.audioPlayer.play()
}
}
.onDisappear() {
self.audioPlayer.pause()
}
}
}
任何时候你使用 !,如果该值最终为零,你就有崩溃的风险。这里最简单的解决方案是使 audioPlayer 成为可选的。
其次,关于重叠音频的问题,标签可能没有真正卸载(也没有调用 onDisappear
)。除了使用 onAppear
和 onDisappear
,您还可以使用 onChange
并观察 TabView
的选择(为简洁起见,删除了一些 AudioPlayer
代码):
struct ManualView: View {
let titleText = ["Willkommen", "Kategorien", "Neuigkeiten","Beispiel", "star.fill","cart", "star.fill","cart", "star.fill"]
let titleImage = ["character.book.closed.fill", "list.dash", "megaphone.fill","moon.zzz.fill", "star.fill","cart", "star.fill","cart", "star.fill"]
let soundFile = ["WelcomePage","CategoryPage", "NewsPage", "ExamplePage","WelcomePage", "WelcomePage", "WelcomePage","WelcomePage", "WelcomePage", "WelcomePage"]
@State private var selection = -1
var body: some View {
TabView(selection: $selection) {
ForEach(0..<4) { value in
OnboardingPage(soundFile: soundFile[value],
title: titleText[value],
image: titleImage[value],
isActive: selection == value)
.tag(value)
}
}
.tabViewStyle(.page(indexDisplayMode: .always))
.onAppear {
selection = 0 //trick to get onChange triggered on first screen
}
}
}
struct OnboardingPage: View {
var soundFile: String
let title: String
let image: String
var isActive : Bool
@State var audioPlayer: AVAudioPlayer?
var body: some View {
VStack(spacing: 25) {
Text(title)
}
.onChange(of: isActive) { newValue in
if newValue {
print("Play \(title)")
audioPlayer?.play()
} else {
print("Stop \(title)")
audioPlayer?.stop()
}
}
}
}