问题描述
我有一个带有媒体项目列表的 collectionView(一个视频链接和其余音频)。当一个项目被点击时,该 url 被加载到 AVPlayer 中进行播放,并且一个 mediaPlayer 视图控制器以模态呈现与播放控件。当用户向下滑动模式 mediaPlayerVC 时,音频会继续按预期播放。但是,当用户点击媒体项目(可能与正在播放的内容相同或不同)或 nowPlaying 标签时,模式 mediaPlayerVC 将再次呈现,但在加载 url 时音频中存在短暂间隙。很明显,当我在 didSelectRow 和 nowPlayingTapped() 中调用 present(modalVC) 时,avPlayer 被杀死并再次重新加载,因为模式播放器出现。我相信我的问题是在这方面的架构。什么是设置 avPlayer 一次然后让它重新加载一个 url 只有当 url 与当前正在播放的 url 不同时更好的方法?当点击 nowPlaying 时,我只希望 mediaPlayer 以它离开的相同状态再次呈现 - 而不是重新加载 avPlayer。我应该创建一个 AVPlayer 类并以某种方式共享它吗?欢迎提出任何建议。
import AVKit
import MediaPlayer
import UIKit
protocol UpdateNowPlayingButtonDelegate {
func updateNowPlayingButton(station: Station)
}
private let reuseIdentifier = "Cell"
public var avPlayer = AVPlayer()
class MediaCollectionVC: UICollectionViewController,UpdateNowPlayingButtonDelegate {
var stations = [[Station]]()
let mediaVC = MediaPlayerVC()
let stationImages = StationImages()
var nowPlaying: UIButton = {
let nowPlaying = UIButton()
nowPlaying.backgroundColor = .systemRed
nowPlaying.setTitle("Tap a station to play!",for: .normal)
nowPlaying.isUserInteractionEnabled = false
nowPlaying.addTarget(self,action: #selector(nowPlayingTapped),for: .touchUpInside)
return nowPlaying
}()
override func viewDidLoad() {
super.viewDidLoad()
fetchRadioStation()
collectionView.register(MediaCollectionViewCell.self,forCellWithReuseIdentifier: MediaCollectionViewCell.identifier)
collectionView.register(MediaCollectionSectionReusableView.self,forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,withReuseIdentifier: MediaCollectionSectionReusableView.identifier)
collectionView.backgroundColor = .systemBackground
self.title = "Live Media"
navigationController?.modalPresentationStyle = .currentContext
mediaVC.delegate = self
}
override func numberOfSections(in collectionView: UICollectionView) -> Int { stations.count }
override func collectionView(_ collectionView: UICollectionView,numberOfItemsInSection section: Int) -> Int { return stations[section].count }
override func collectionView(_ collectionView: UICollectionView,viewForSupplementaryElementOfKind kind: String,at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionView.elementKindSectionHeader {
let sectionHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind,withReuseIdentifier: MediaCollectionSectionReusableView.identifier,for: indexPath) as! MediaCollectionSectionReusableView
switch indexPath.section {
case 0:
sectionHeader.label.text = "TV"
return sectionHeader
case 1:
sectionHeader.label.text = "News Radio"
return sectionHeader
case 2:
sectionHeader.label.text = "Entertainment Radio"
return sectionHeader
case 3:
sectionHeader.label.text = "Religious Radio"
return sectionHeader
default:
sectionHeader.label.text = "Section Header Issue"
return sectionHeader
}
} else {
print("section header issue")
return UICollectionReusableView()
}
}
override func collectionView(_ collectionView: UICollectionView,cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MediaCollectionViewCell.identifier,for: indexPath) as! MediaCollectionViewCell
let station = stations[indexPath.section][indexPath.row]
cell.titleLabel.text = station.name
cell.imageView.image = stationImages.images[station.name]
return cell
}
override func collectionView(_ collectionView: UICollectionView,didSelectItemAt indexPath: IndexPath) {
nowPlaying.isUserInteractionEnabled = true
let station = stations[indexPath.section][indexPath.row]
let position = indexPath
nowPlaying.setTitle("Now Playing: \(station.name)",for: .normal)
playStream(station: station)
mediaVC.stations = stations
mediaVC.position = position
present(mediaVC,animated: true)
}
@objc func nowPlayingTapped() {
present(mediaVC,animated: true)
}
func updateNowPlayingButton(station: Station) {
nowPlaying.setTitle("Now Playing: \(station.name)",for: .normal)
}
func playStream(station: Station) {
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
try AVAudioSession.sharedInstance().setActive(true)
guard let url = URL(string: station.streamURL) else {
print("url issue")
return
}
avPlayer = AVPlayer(url: url)
if station.medium == "TV" {
let playerController = AVPlayerViewController()
playerController.player = avPlayer
playerController.allowsPictureInPicturePlayback = true
self.present(playerController,animated: true)
avPlayer.play()
} else {
avPlayer.play()
}
} catch {
print("error: \(error)")
}
}
func fetchRadioStation() {
let baseURL = ""
guard let url = URL(string: baseURL) else {
print("station list URL invalid")
return
}
let session = URLSession(configuration: .default)
session.dataTask(with: url) { data,response,error in
if error != nil {
print(error ?? "error fetching stations")
return
}
if let safeData = data {
self.parseJSON(data: safeData)
}
}.resume()
}
func parseJSON(data: Data) {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(StationData.self,from: data)
let newsData = decodedData.stations
DispatchQueue.main.async {
self.stations.append(newsData.filter { $0.category == "News" && $0.medium == "TV"})
self.stations.append(newsData.filter { $0.medium == "Radio" && $0.category == "News"})
self.stations.append(newsData.filter { $0.medium == "Radio" && $0.category == "Entertainment"})
self.stations.append(newsData.filter { $0.medium == "Radio" && $0.category == "Religious"})
self.collectionView.reloadData()
}
print("all stations loaded successfully")
} catch {
print("Error decoding: \(error)")
}
}
}
// Media Player VC
import AVFoundation
import AVKit
import MediaPlayer
import UIKit
protocol setNowPlaying: MediaCollectionVC {
func didSetNowPlaying(stationName: String)
}
class MediaPlayerVC: UIViewController {
public var position: IndexPath = []
public var stations = [[Station]]()
var stationImages = StationImages()
var player: AVPlayer?
var isPlaying: Bool = true
var delegate: UpdateNowPlayingButtonDelegate?
var nowPlayingInfo = [String : Any]()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
configure()
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
let station = stations[position.section][position.row]
setupNotificationView(station: station)
setupMediaPlayerNotificationView()
//configure()
}
func updateUI(station: Station) {
stationImageView.image = stationImages.images[station.name]
stationNameLabel.text = station.name
}
func configure() {
let station = stations[position.section][position.row]
delegate?.updateNowPlayingButton(station: station)
updateUI(station: station)
setupNotificationView(station: station)
avPlayer = AVPlayer(url: URL(string: station.streamURL)!)
avPlayer.play()
playPauseButton.addTarget(self,action: #selector(playPauseButtonTapped(_:)),for: .touchUpInside)
nextButton.addTarget(self,action: #selector(nextButtonTapped(_:)),for: .touchUpInside)
backButton.addTarget(self,action: #selector(backButtonTapped(_:)),for: .touchUpInside)
}
func setupMediaPlayerNotificationView() {
let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.playCommand.addTarget { [unowned self] event in
avPlayer.play()
isPlaying.toggle()
return .success
}
commandCenter.pauseCommand.addTarget { [unowned self] event in
avPlayer.pause()
isPlaying.toggle()
return .success
}
commandCenter.previousTrackCommand.addTarget { [unowned self] event in
self.backButtonTapped(backButton)
return .success
}
commandCenter.nextTrackCommand.addTarget { [unowned self] event in
self.nextButtonTapped(nextButton)
return .success
}
}
func setupNotificationView(station: Station) {
nowPlayingInfo[MPMediaItemPropertyTitle] = "\(station.name)"
MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
}
@objc func playPauseButtonTapped(_ button: UIButton) {
avPlayer.play()
isPlaying.toggle()
if isPlaying == true {
playPauseButton.setBackgroundImage(UIImage(systemName: "pause"),for: .normal)
} else {
avPlayer.pause()
playPauseButton.setBackgroundImage(UIImage(systemName: "play"),for: .normal)
}
}
@objc func nextButtonTapped(_ button: UIButton) {
if position.section == stations.count - 1 {
if position.row == stations[position.section].count - 1 {
position.section = 1
position.row = 0
configure()
} else {
position.row += 1
configure()
}
} else {
if position.row < stations[position.section].count - 1 {
position.row += 1
configure()
} else {
position.section += 1
position.row = 0
configure()
}
}
}
@objc func backButtonTapped(_ button: UIButton) {
if position != [1,0] {
if position.row > 0 {
position.row -= 1
configure()
} else {
position.section -= 1
position.row = stations[position.section].count - 1
configure()
}
} else {
position.section = stations.count - 1
position.row = stations[position.section].count - 1
configure()
}
}
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)