// // PlayerViewController.swift // MusicPlayer // // Created by Mr.Zhou on 2024/3/28. // import UIKit ///播放器显示状态 enum MPSideA_PlayerState { case Dark case Light ///对应的按钮背景色 var buttonBGColor:UIColor{ switch self { case .Dark: return .init(hex: "#FFFFFF", alpha: 0.15) case .Light: return .init(hex: "#F2F2F2") } } ///页面背景色 var viewBGColor:UIColor{ switch self { case .Dark: return .init(hex: "#000000") case .Light: return .init(hex: "#FFFFFF") } } ///文本字体颜色 var textColor:UIColor{ switch self { case .Dark: return .init(hex: "#FFFFFF") case .Light: return .init(hex: "#000000") } } ///滑块图片 var thumbImage:UIImage{ switch self { case .Dark: return UIImage(named: "Thumb dark'logo")! case .Light: return UIImage(named: "Thumb light'logo")! } } ///滑轨颜色集合 var minTrackColors:[UIColor]{ switch self { case .Dark: return [UIColor(hex: "#FFFFFF", alpha: 0.3), UIColor(hex: "#FFFFFF", alpha: 0.3)] case .Light: return [UIColor(hex: "#80F988", alpha: 0.2), UIColor(hex: "#80F988", alpha: 0.2)] } } ///毛玻璃效果 var effctView:UIBlurEffect{ switch self { case .Dark: if #available(iOS 13.0, *) { return UIBlurEffect(style: .systemThickMaterialDark) } else { return UIBlurEffect(style: .dark) } case .Light: return UIBlurEffect(style: .light) } } } ///播放器页面 @objcMembers class MPSideA_PlayerViewController: MPSideA_BaseViewController { @IBOutlet weak var disMissBtn: UIButton! @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var effectView: UIVisualEffectView! @IBOutlet weak var backImageView: UIImageView! @IBOutlet weak var coverImageView: UIImageView! @IBOutlet weak var nameLabel: UILabel! @IBOutlet weak var slider: MP_PlayerSlider!{ didSet{ slider.thumbImage = state.thumbImage slider.trackHeight = 10*width slider.minTrackColors = state.minTrackColors slider.minTrackLocations = [0.0,1.0] slider.maxTrackColors = state.minTrackColors slider.maxTrackLocations = [0.0,1.0] slider.setNeedsDisplay() } } @IBOutlet weak var volumeLabel: UILabel! @IBOutlet weak var lampView: MPSideA_PlayerActionView!{ didSet{ lampView.darkImage = UIImage(named: "Lamp dark'logo") lampView.lightImage = UIImage(named: "Lamp light'logo") lampView.isDark = true lampView.isPlaying = false lampView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(lampActionClick(_ :)))) } } @IBOutlet weak var timerView: MPSideA_PlayerActionView!{ didSet{ timerView.darkImage = UIImage(named: "Timer dark'logo") timerView.lightImage = UIImage(named: "Timer light'logo") timerView.playingImage = UIImage(named: "Timer playing'logo") timerView.isDark = true timerView.isPlaying = false timerView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(timerActionClick(_ :)))) } } @IBOutlet weak var timerLabel: UILabel! @IBOutlet weak var autoView: MPSideA_PlayerActionView!{ didSet{ autoView.darkImage = UIImage(named: "Auto dark'logo") autoView.lightImage = UIImage(named: "Auto light'logo") autoView.playingImage = UIImage(named: "Auto playing'logo") autoView.isDark = true autoView.isPlaying = false autoView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(autoActionClick(_ :)))) } } @IBOutlet weak var playBtn: UIButton! @IBOutlet weak var maskView: UIImageView! //图片旋转计时器 private var timer:CADisplayLink! //播放器页面显示状态,默认为黑夜(切换后对于页面内容作出改变) private lazy var state:MPSideA_PlayerState = .Dark{ didSet{ setUpState(state) } } //当前系统音量 private lazy var volume:Float = 0{ didSet{ //更新label值 volumeLabel.text = String(format: "Volume:%.2f", volume*100) //调整slider let value = volume slider.value = value } } //指定自动播放需要的分贝值 private lazy var decibels:Float = 0.5 override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = state.viewBGColor playBtn.isSelected = MPSideA_MediaCenterManager.shared.getPlayerState() == .Playing //启动音量绑定 MPSideA_VolumeManager.shared.createVolume() //设置音量 volume = MPSideA_VolumeManager.shared.getVolume() if let music = MPSideA_MediaCenterManager.shared.getMusic() { //设置音乐展示 nameLabel.text = music.title coverImageView.image = UIImage(data: music.cover) backImageView.image = UIImage(data: music.cover) } lampView.backgroundColor = state.buttonBGColor timerView.backgroundColor = state.buttonBGColor autoView.backgroundColor = state.buttonBGColor //触发音乐缺失闭包 nullMusicAction = { [weak self] in //退出该页面 self?.navigationController?.popViewController(animated: true) } //初始化计时器 timer = CADisplayLink(target: self, selector: #selector(coverRotationalAction(_ :))) //一秒执行多少次 timer.preferredFramesPerSecond = 20 //开辟线程 timer.add(to: RunLoop.current, forMode: .common) timer.isPaused = true addNotification() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) //根据播放器状态设置计时器状态 timer.isPaused = !(MPSideA_MediaCenterManager.shared.getPlayerState() == .Playing) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) //停止监听器 MPSideA_MediaCenterManager.shared.stopMonitor() } deinit { //移除所有通知 NotificationCenter.default.removeObserver(self) //销毁音量绑定 MPSideA_VolumeManager.shared.destroyVolume() //销毁帧计时器 timer = nil } //添加通知与监听 private func addNotification() { //添加通知 NotificationCenter.notificationKey.add(observer: self, selector: #selector(timesAction(_ :)), notificationName: .sideA_time_times) NotificationCenter.notificationKey.add(observer: self, selector: #selector(volumeChangeAction(_ :)), notificationName: .sideA_volume_change) NotificationCenter.notificationKey.add(observer: self, selector: #selector(playMusicAction(_ :)), notificationName: .sideA_play_music) NotificationCenter.notificationKey.add(observer: self, selector: #selector(pauseMusicAction(_ :)), notificationName: .sideA_pause_music) NotificationCenter.notificationKey.add(observer: self, selector: #selector(resumeMusicAction(_ :)), notificationName: .sideA_resume_music) NotificationCenter.notificationKey.add(observer: self, selector: #selector(stopMusicAction(_ :)), notificationName: .sideA_stop_music) NotificationCenter.notificationKey.add(observer: self, selector: #selector(fileMissAction(_ :)), notificationName: .sideA_null_music) NotificationCenter.notificationKey.add(observer: self, selector: #selector(openMonitorAction(_ :)), notificationName: .sideA_open_monitor) NotificationCenter.notificationKey.add(observer: self, selector: #selector(stopMonitorAction(_ :)), notificationName: .sideA_stop_monitor) } } //MARK: - 交互事件 extension MPSideA_PlayerViewController { //退出事件 @IBAction func disMissAction(_ sender: UIButton) { dismiss(animated: true) } //手动调整音量 @IBAction func sliderVolumeAction(_ sender: MP_PlayerSlider) { let value = sender.value MPSideA_VolumeManager.shared.setVolume(value) } //切换页面显示状态 @objc private func lampActionClick(_ sender: MPSideA_PlayerActionView) { if state == .Dark { state = .Light }else { state = .Dark } } //设置倒计时 @objc private func timerActionClick(_ sender: MPSideA_PlayerActionView) { //关闭麦克风监听器 MPSideA_MediaCenterManager.shared.stopMonitor() MPSideA_ModalType = .Timer let timerVC = MPSideA_CountTimerViewController() timerVC.transitioningDelegate = self timerVC.modalPresentationStyle = .custom present(timerVC, animated: true) } //自动播放(当环境分贝超过指定值时播放) @objc private func autoActionClick(_ sender: MPSideA_PlayerActionView) { guard authorize(observe: self) == true else { print("No Microphone Access") return } if autoView.isPlaying { //关闭麦克风监听器 MPSideA_MediaCenterManager.shared.stopMonitor() }else { //启动监听器 MPSideA_MediaCenterManager.shared.openMonitor(0.5) } } //播放/暂停 @IBAction func playClick(_ sender: UIButton) { //关闭麦克风监听器 MPSideA_MediaCenterManager.shared.stopMonitor() guard let music = MPSideA_MediaCenterManager.shared.getMusic() else { //播放器未能持有音乐实体 print("No Data Music") return } switch MPSideA_MediaCenterManager.shared.getPlayerState() { case .Null://启动播放 MPSideA_MediaCenterManager.shared.playerStart(music, actionType: .Normal) case .Playing://暂停播放 MPSideA_MediaCenterManager.shared.playerPause() case .Pause://继续播放 MPSideA_MediaCenterManager.shared.playerResume() } } } //MARK: - 业务处理 extension MPSideA_PlayerViewController: UIViewControllerTransitioningDelegate { //声音值切换 @objc fileprivate func volumeChangeAction(_ sender:Notification) { guard let value = sender.object as? Float else { return } volume = value } //页面状态切换 private func setUpState(_ state:MPSideA_PlayerState) { view.backgroundColor = state.viewBGColor //黑夜展示背景图,白天隐藏 backImageView.isHidden = !(state == .Dark) maskView.isHidden = !(state == .Dark) titleLabel.textColor = state.textColor //调整毛玻璃 effectView.effect = state.effctView nameLabel.textColor = state.textColor slider.thumbImage = state.thumbImage slider.minTrackColors = state.minTrackColors slider.maxTrackColors = state.minTrackColors slider.setNeedsDisplay() volumeLabel.textColor = state.textColor //更改按钮的背景色 disMissBtn.backgroundColor = state.buttonBGColor lampView.backgroundColor = state.buttonBGColor timerView.backgroundColor = state.buttonBGColor autoView.backgroundColor = state.buttonBGColor //更改按钮的高亮 disMissBtn.isSelected = !(state == .Dark) lampView.isDark = (state == .Dark) timerView.isDark = (state == .Dark) autoView.isDark = (state == .Dark) } //计时值变化事件 @objc private func timesAction(_ sender:Notification) { DispatchQueue.main.async { [weak self] in guard let self = self else { return } let time = sender.object as! TimeInterval timerView.isPlaying = true timerLabel.isHidden = false timerLabel.text = setTimesToMins(time) } } //计时结束事件 @objc private func completeAction(_ sender:Notification) { DispatchQueue.main.async { [weak self] in guard let self = self else { return } timerView.isPlaying = false timerLabel.isHidden = true timerLabel.text = "00" } } //启动音乐播放器 @objc private func playMusicAction(_ sender:Notification) { DispatchQueue.main.async { [weak self] in guard let self = self else { return } playBtn.isSelected = true autoView.isPlaying = false //旋转图片 coverImageView.transform = .identity timer.isPaused = false } } //暂停音乐播放器 @objc private func pauseMusicAction(_ sender:Notification) { DispatchQueue.main.async { [weak self] in guard let self = self else { return } playBtn.isSelected = false timer.isPaused = true } } //继续音乐播放器 @objc private func resumeMusicAction(_ sender:Notification) { DispatchQueue.main.async { [weak self] in guard let self = self else { return } playBtn.isSelected = true timer.isPaused = false } } //终止音乐播放器 @objc private func stopMusicAction(_ sender:Notification) { DispatchQueue.main.async { [weak self] in guard let self = self else { return } playBtn.isSelected = false timerView.isPlaying = false timerLabel.isHidden = true timerLabel.text = "00" timer.isPaused = true coverImageView.transform = .identity } } //开启麦克风监听器 @objc private func openMonitorAction(_ sender:Notification) { DispatchQueue.main.async { [weak self] in guard let self = self else { return } autoView.isPlaying = true } } //关闭麦克风监听器 @objc private func stopMonitorAction(_ sender:Notification) { DispatchQueue.main.async { [weak self] in guard let self = self else { return } autoView.isPlaying = false } } //计时器事件-封面图片随着音乐播放器状态旋转自身 @objc private func coverRotationalAction(_ link:CADisplayLink) { //当音乐播放器启动后,使得封面图片无限旋转,当音乐播放器暂停/结束后,图片会回正 DispatchQueue.main.async { [weak self] in guard let self = self else { return } let angle = CGFloat.pi / 200 coverImageView.transform = coverImageView.transform.rotated(by: angle) } } func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { return MPSideA_PresentationController(presentedViewController: presented, presenting: presenting) } }