当用户在应用程序中移动时如何继续播放音乐。 [不在后台模式]
How to continuing playing music when user move through the app. [Not in background mode]
我正在 Swift 中制作一个基于 Tab Bar Controller 的 musicPlayer 应用程序,现在正在创建 NowPlayingViewController,它呈现如下屏幕截图所示的播放场景。当我单击另一个 tableViewController 的 table 行并播放该歌曲时,将打开此 NowPlayingViewController。
我的问题是,当我关闭此 View Controller 以返回上一个视图或移动到 Tab Bar Controller 的其他视图时,音乐播放停止了。经过一些谷歌搜索,有人建议使用 singleton 来创建一个共享会话来播放音乐。
/// 这是我项目的故事板
/// 我更改我的代码以添加一个 音频 Manager.swift 作为单例 class。但是我不确定我是否做对了,需要帮助。也没有找到从 NowPlayingVewController 获取 playingSong 变量的方法...
import AVKit
class AudioManager {
// use Singleton pattern keep the music continuing when user move through the App.
static let sharedInstance = AudioManager()
var audioPlayer: AVAudioPlayer!
var playingSong: SongData?
private init() {
// config for audio background playing
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers])
print("Playback OK")
try AVAudioSession.sharedInstance().setActive(true)
print("Session is Active")
} catch {
print(error)
}
}
func startMusic() {
do {
// how to retrieve the playingSong variable from NowPlayingViewController?
// playingSong =
try audioPlayer = AVAudioPlayer(contentsOf: playingSong!.url)
audioPlayer.prepareToPlay()
audioPlayer.play()
} catch {
print("could not load file")
}
}
func pauseMusic() {
audioPlayer.pause()
}
}
/// NowPlayViewController.swift,以防与上图不完全对齐,因为它只是展示播放场景的示例图像。
import UIKit
import AVKit
class NowPlayingViewController: UIViewController {
var playingSong: SongData?
var audioPlayer: AVAudioPlayer!
var isPlaying = true
var timer:Timer!
@IBOutlet weak var songTitle: UILabel!
@IBOutlet weak var songAlbum: UILabel!
@IBOutlet weak var songArtwork: UIImageView!
@IBOutlet weak var playOrPauseButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
songTitle.text = playingSong?.songName
songAlbum.text = playingSong?.albumName
songArtwork.image = playingSong?.albumArtwork
// start play music in AudioManager sharedInstance
AudioManager.sharedInstance.startMusic()
}
@IBAction func NaviBack(_ sender: UIButton) {
print("press button")
// not sure about this, use present modally of segue,
// so need to use dismiss to return to the previous scene/view.
self.dismiss(animated: true, completion: nil)
}
@IBAction func PlayOrPauseMusic(_ sender: UIButton) {
if isPlaying {
print("isPlaying")
AudioManager.sharedInstance.pauseMusic()
isPlaying = false
playOrPauseButton.setTitle("Pause", for: .normal)
} else {
print("isPaused")
AudioManager.sharedInstance.startMusic()
isPlaying = true
playOrPauseButton.setTitle("Play", for: .normal)
}
}
}
/// 使用 Segue 模态呈现从 tableViewController 向 NowPlayingViewController 发送数据。
// define segue to the transition to NowPlaying View
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "playingSong" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let controller = segue.destination as! NowPlayingViewController
if resultSearchController.isActive {
controller.playingSong = filteredTableData[indexPath.row]
} else {
controller.playingSong = tableData[indexPath.row]
}
}
}
}
糟糕,当用户单击此视图中的单元格行时,我发现我的 AudioManger 实际上是通过从 tableViewController 获取 playingSong: SongData 来工作的。我将此 playingSong 声明为静态变量,以便从 AudioManager access/use 它。
现在当用户通过标签栏控制器导航时正在播放音乐,更新我的代码如下。下一步可以在导航视图的 left/right 顶部添加一个按钮来重新呈现播放场景:)
呃,我发现它仍然有问题,当前歌曲的播放和恢复工作正常,但是如果我 select 在 tableViewController 中播放另一首歌曲,那么它仍然会在 NowPlayingView 中播放上一首歌曲。原因可能是 init() 只有一次,所以我需要找到一种方法在 select 另一个单元格行时将值重新分配给 sharedInstance。
import AVKit
class AudioManager {
// use Singleton pattern keep the music continuing when user move through the App.
static let sharedInstance = AudioManager()
var audioPlayer: AVAudioPlayer!
var playingSong: SongData?
private init() {
// config for audio background playing
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers])
print("Playback OK")
try AVAudioSession.sharedInstance().setActive(true)
print("Session is Active")
} catch {
print(error)
}
do {
playingSong = SongsTableViewController.playingSong
try audioPlayer = AVAudioPlayer(contentsOf: playingSong!.url)
audioPlayer.prepareToPlay()
} catch {
print("could not load file")
}
}
func playMusic() {
audioPlayer.play()
}
func pauseMusic() {
audioPlayer.pause()
}
}
我正在 Swift 中制作一个基于 Tab Bar Controller 的 musicPlayer 应用程序,现在正在创建 NowPlayingViewController,它呈现如下屏幕截图所示的播放场景。当我单击另一个 tableViewController 的 table 行并播放该歌曲时,将打开此 NowPlayingViewController。
我的问题是,当我关闭此 View Controller 以返回上一个视图或移动到 Tab Bar Controller 的其他视图时,音乐播放停止了。经过一些谷歌搜索,有人建议使用 singleton 来创建一个共享会话来播放音乐。
/// 这是我项目的故事板
/// 我更改我的代码以添加一个 音频 Manager.swift 作为单例 class。但是我不确定我是否做对了,需要帮助。也没有找到从 NowPlayingVewController 获取 playingSong 变量的方法...
import AVKit
class AudioManager {
// use Singleton pattern keep the music continuing when user move through the App.
static let sharedInstance = AudioManager()
var audioPlayer: AVAudioPlayer!
var playingSong: SongData?
private init() {
// config for audio background playing
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers])
print("Playback OK")
try AVAudioSession.sharedInstance().setActive(true)
print("Session is Active")
} catch {
print(error)
}
}
func startMusic() {
do {
// how to retrieve the playingSong variable from NowPlayingViewController?
// playingSong =
try audioPlayer = AVAudioPlayer(contentsOf: playingSong!.url)
audioPlayer.prepareToPlay()
audioPlayer.play()
} catch {
print("could not load file")
}
}
func pauseMusic() {
audioPlayer.pause()
}
}
/// NowPlayViewController.swift,以防与上图不完全对齐,因为它只是展示播放场景的示例图像。
import UIKit
import AVKit
class NowPlayingViewController: UIViewController {
var playingSong: SongData?
var audioPlayer: AVAudioPlayer!
var isPlaying = true
var timer:Timer!
@IBOutlet weak var songTitle: UILabel!
@IBOutlet weak var songAlbum: UILabel!
@IBOutlet weak var songArtwork: UIImageView!
@IBOutlet weak var playOrPauseButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
songTitle.text = playingSong?.songName
songAlbum.text = playingSong?.albumName
songArtwork.image = playingSong?.albumArtwork
// start play music in AudioManager sharedInstance
AudioManager.sharedInstance.startMusic()
}
@IBAction func NaviBack(_ sender: UIButton) {
print("press button")
// not sure about this, use present modally of segue,
// so need to use dismiss to return to the previous scene/view.
self.dismiss(animated: true, completion: nil)
}
@IBAction func PlayOrPauseMusic(_ sender: UIButton) {
if isPlaying {
print("isPlaying")
AudioManager.sharedInstance.pauseMusic()
isPlaying = false
playOrPauseButton.setTitle("Pause", for: .normal)
} else {
print("isPaused")
AudioManager.sharedInstance.startMusic()
isPlaying = true
playOrPauseButton.setTitle("Play", for: .normal)
}
}
}
/// 使用 Segue 模态呈现从 tableViewController 向 NowPlayingViewController 发送数据。
// define segue to the transition to NowPlaying View
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "playingSong" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let controller = segue.destination as! NowPlayingViewController
if resultSearchController.isActive {
controller.playingSong = filteredTableData[indexPath.row]
} else {
controller.playingSong = tableData[indexPath.row]
}
}
}
}
糟糕,当用户单击此视图中的单元格行时,我发现我的 AudioManger 实际上是通过从 tableViewController 获取 playingSong: SongData 来工作的。我将此 playingSong 声明为静态变量,以便从 AudioManager access/use 它。
现在当用户通过标签栏控制器导航时正在播放音乐,更新我的代码如下。下一步可以在导航视图的 left/right 顶部添加一个按钮来重新呈现播放场景:)
呃,我发现它仍然有问题,当前歌曲的播放和恢复工作正常,但是如果我 select 在 tableViewController 中播放另一首歌曲,那么它仍然会在 NowPlayingView 中播放上一首歌曲。原因可能是 init() 只有一次,所以我需要找到一种方法在 select 另一个单元格行时将值重新分配给 sharedInstance。
import AVKit
class AudioManager {
// use Singleton pattern keep the music continuing when user move through the App.
static let sharedInstance = AudioManager()
var audioPlayer: AVAudioPlayer!
var playingSong: SongData?
private init() {
// config for audio background playing
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers])
print("Playback OK")
try AVAudioSession.sharedInstance().setActive(true)
print("Session is Active")
} catch {
print(error)
}
do {
playingSong = SongsTableViewController.playingSong
try audioPlayer = AVAudioPlayer(contentsOf: playingSong!.url)
audioPlayer.prepareToPlay()
} catch {
print("could not load file")
}
}
func playMusic() {
audioPlayer.play()
}
func pauseMusic() {
audioPlayer.pause()
}
}