如何从歌曲的分钟数正确倒计时?
Posted
技术标签:
【中文标题】如何从歌曲的分钟数正确倒计时?【英文标题】:how to properly do a countDown from the minutes of a Song? 【发布时间】:2019-05-24 17:11:41 【问题描述】:-
我想知道如何正确获取歌曲的总分和秒。一旦我得到总的分钟和秒数,我希望它开始倒计时。只需显示 2 位小数秒和两位小数。
我想知道怎么从头数数
并且还想显示 2 位小数秒和 2 位分钟
提前致谢
@objc func timerUpdate()
if (player != nil && player!.currentTime > 0.0)
increaseTime ()
DecreaseTime()
progressBar.setProgress(Float(player!.currentTime / player!.duration), animated: false)
else
timer.invalidate()
var totalOfTime :Double?
var minutes : Double?
var seconds : Double?
func changeSecondToMinutes()
minutes = player!.duration / 60.0
seconds = minutes! / 60
seconds! *= 100
var rightOfSecods = Int(round(seconds!))
seconds = Double(rightOfSecods) * 00.01
print(seconds!)
var time = 0
var minut = 0
func increaseTime ()
startTime.text = "\(Double(minut)) "
print(minut)
print(time)
var secondos = 0.0
func DecreaseTime()
seconds! -= 0.010
print(seconds!)
print(minutes!)
if Double(round(10000*seconds!)/10000) == 0.00
seconds! += 0.60
minutes! -= 1
time += 1
print(secondos)
if time == 61
minut += 1
time = 0
func PlayerFunction()
changeSecondToMinutes()
Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(timerUpdate), userInfo: nil, repeats: true)
【问题讨论】:
Format float value with 2 decimal places的可能重复 有什么建议,请提供代码 【参考方案1】:我在我的项目中使用这个单例类
class MediaPlayerManager: NSObject
static let shared = MediaPlayerManager()
private var _player = AVPlayer()
private var _timer = Timer()
private var _songURL = ""
private var _isPaused = false
private var _isPlaying = false
private var _isStopped = false
private var _isRepeatEnabled = false
private var _isShuffleEnabled = false
private var _songProgressed : Float = 0.0
private var _observer: Any!
private var _rate: Float = 1.0
var songURL : String
set _songURL = newValue
get return _songURL
var isPaused : Bool
set _isPaused = newValue
get return _isPaused
var isPlaying : Bool
set _isPlaying = newValue
get return _isPlaying
var isRepeatEnabled : Bool
set _isRepeatEnabled = newValue
get return _isRepeatEnabled
var isShuffleEnabled : Bool
set _isShuffleEnabled = newValue
get return _isShuffleEnabled
var songProgressed : Float
set _songProgressed = newValue
get return _songProgressed
var rate : Float
set
_rate = newValue
_player.rate = _rate
get return _rate
override init()
super.init()
do
try AVAudiosession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers, .allowAirPlay])
print("Playback OK")
try AVAudioSession.sharedInstance().setActive(true)
print("Session is Active")
catch
print(error)
_player = AVPlayer.init()
func playSong()
if isPaused
_player.play()
isPlaying = true
isPaused = false
return
isPlaying = true
isPaused = false
let url = URL(string: self.songURL)
let item = AVPlayerItem(url: url!)
_player = AVPlayer(playerItem: item)
_player.play()
isPlaying = true
isPaused = false
addObserver()
func playSong(urlString: String)
let url = URL(string: urlString)
songURL = urlString
if isPaused
_player.play()
isPlaying = true
isPaused = false
return
isPlaying = true
isPaused = false
let item = AVPlayerItem(url: url!)
_player = AVPlayer(playerItem: item)
_player.play()
addObserver()
func addObserver()
_player.addObserver(self, forKeyPath: "rate", options: NSKeyValueObservingOptions.new, context: nil)
_player.currentItem!.addObserver(self, forKeyPath: "playbackBufferEmpty", options: .new, context: nil)
_player.currentItem!.addObserver(self, forKeyPath: "playbackLikelyToKeepUp", options: .new, context: nil)
_player.currentItem!.addObserver(self, forKeyPath: "playbackBufferFull", options: .new, context: nil)
let interval = CMTime(value: 1, timescale: 2)
_observer = _player.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main, using: (progressTime) in
self.scheduleTimer()
let seconds = CMTimeGetSeconds(progressTime)
let secondsString = String(format: "%02d", Int(seconds.truncatingRemainder(dividingBy: 60.0)))
let minutesString = String(format: "%02d", Int(seconds / 60))
print( "\(minutesString):\(secondsString)" )
self.songProgressed = Float( seconds )
)
func pauseSong()
if isPlaying
isPlaying = false
isPaused = true
_player.pause()
func stopSong()
isPlaying = false
isPaused = false
invalidateTimer()
if let observer = _observer
_player.removeTimeObserver(observer)
_observer = nil
_player = AVPlayer.init()
func reset()
songURL = ""
stopSong()
func seekTo(Time time: Double)
let seconds : Int64 = Int64(time)
let targetTime: CMTime = CMTimeMake(value: seconds, timescale: 1)
_player.seek(to: targetTime)
func getRemainingTime() -> Double
let duration = _player.currentItem!.duration.seconds //total time
let currentTime = _player.currentTime().seconds //playing time
let remainingTime = duration - currentTime
return (remainingTime.isNaN || remainingTime.isInfinite) ? 0 : remainingTime
func getSongDuration() -> Double
return (_player.currentItem!.duration.seconds.isNaN || _player.currentItem!.duration.seconds.isInfinite) ? 0 : _player.currentItem!.duration.seconds
func getSongProgress() -> Double
return (Double(self.songProgressed).isNaN || Double(self.songProgressed).isInfinite) ? 0 : Double(self.songProgressed)
private func scheduleTimer()
if (!_timer.isValid)
_timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true)
private func invalidateTimer()
_timer.invalidate()
@objc func updateTimer()
NotificationCenter.default.post(name: .didReceiveRemainingTime, object: nil, userInfo: [Notification.Name.didReceiveRemainingTime: getRemainingTime()])
NotificationCenter.default.post(name: .didReceiveElapsedTime, object: nil, userInfo: [Notification.Name.didReceiveElapsedTime: getSongProgress()])
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
switch keyPath
case "rate":
if let rate = change?[NSKeyValueChangeKey.newKey] as? Float
if rate == 0.0
print("playback stopped")
isPlaying = false
isPaused = true
invalidateTimer()
if rate == 1.0
print("normal playback")
if rate == -1.0
print("reverse playback")
case "playbackBufferEmpty":
// Show loader
print("buffer empty")
case "playbackLikelyToKeepUp":
// Hide loader
print("buffer")
case "playbackBufferFull":
// Hide loader
print("buffer full")
case .none:
break
case .some(_):
break
这是你如何使用这个类并获得剩余时间
override func viewDidLoad()
super.viewDidLoad()
addMediaPlayerObservers()
func addMediaPlayerObservers()
NotificationCenter.default.addObserver(self, selector: #selector(didReceiveRemainingTime), name: NSNotification.Name.didReceiveRemainingTime, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(didReceiveElapsedTime), name: NSNotification.Name.didReceiveElapsedTime, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(didSongFinished(_:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
func playSong()
MediaPlayerManager.shared.playSong(urlString: "song url here")
@objc func didReceiveRemainingTime(_ notification: NSNotification)
if let remainingTime = notification.userInfo?[NSNotification.Name.didReceiveRemainingTime] as? Double
// print("Remaining time from observer: \(remainingTime)")
self.hmsFrom(seconds: (Int)(remainingTime)) (hours, minutes, seconds) in
print("hours: \(hours)")
print("minutes: \(minutes)")
print("seconds: \(seconds)")
@objc func didReceiveElapsedTime(_ notification: NSNotification)
if let elapsedTime = notification.userInfo?[NSNotification.Name.didReceiveElapsedTime] as? Double
// print("Elapsed time from observer: \(elapsedTime)")
self.hmsFrom(seconds: (Int)(elapsedTime)) (hours, minutes, seconds) in
print("hours: \(hours)")
print("minutes: \(minutes)")
print("seconds: \(seconds)")
@objc func didSongFinished(_ notification: NSNotification)
print("Finished")
MediaPlayerManager.shared.stopSong()
这个函数实际上将总秒数分别转换为小时、分钟和秒
func hmsFrom(seconds: Int, completion: @escaping (_ hours: Int, _ minutes: Int, _ seconds: Int)->())
completion(seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60)
这是通知扩展
extension Notification.Name
static let didReceiveRemainingTime = Notification.Name("didReceiveRemainingTime")
static let didReceiveElapsedTime = Notification.Name("didReceiveElapsedTime")
希望你能得到想要的结果。
【讨论】:
嗨,我如何将 player.duration 转换为 CMTimeGetSeconds,我遇到了问题,请提前提供代码,谢谢 让时间 = CMTimeGetSeconds(_player.currentItem!.duration) if let duration = player?.duration print(duration) let totalOfSeconds = CMTimeGetSeconds(duration) 我也尝试调用 player.currentItem.duration 并且它没有 currentItem 属性,我正在使用AV音频播放器?作为我的玩家 guard let player = player else return let remainingTime = Int(player.duration - player.currentTime) print(remainingTime) let remainingTimeCMTimeObj = CMTimeGetSeconds(CMTime(seconds: Double(remainingTime), preferredTimescale: CMTimeScale.init(Double(remainingTime)))) 打印(remainingTimeCMTimeObj) remainingTime 是 Integer,remainingTimeCMTimeObj 是您需要的 CMTimeGetSeconds,其中 as player 是 AVAudioPlayer【参考方案2】:看起来DateComponenetsFormatter
加上一些强制转换是一个很好的例子。
var player : AVPlayerItem? //Assuming you initialized this correctly.
var timer : Timer?
@objc func timerUpdate()
if let currentTime = player?.currentTime(), let duration = player?.duration, duration != CMTime.zero
let timeLeft = duration - currentTime
//https://***.com/a/43890305/5153744
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute, .second]
formatter.unitsStyle = .positional
let formattedCurrentTime = formatter.string(from: TimeInterval(CMTimeGetSeconds(currentTime)))!
let formattedTimeLeft = formatter.string(from: TimeInterval(CMTimeGetSeconds(timeLeft)))!
let formattedTimeDuration = formatter.string(from: TimeInterval(CMTimeGetSeconds(duration)))!
print("Current Time: \(formattedCurrentTime)")
print("Time Left: \(formattedTimeLeft)")
print("TotalDuration: \(formattedTimeDuration)")
else
timer?.invalidate()
func playerFunction()
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(timerUpdate), userInfo: nil, repeats: true)
【讨论】:
播放器是 var player: AVAudioPlayer?我应该为 AVPlayerItem 更改它吗? 不,我不知道它是哪种资产,所以我只需要根据您的代码做出假设,因为您没有发布您的实例化。AVPlayerItem
具有我用来计算的相同属性,所以不,你不需要。
它不允许转换 CMTimeGetSeconds(currentTime) 我该怎么做是因为它是一个 AVAudioPlayer?以上是关于如何从歌曲的分钟数正确倒计时?的主要内容,如果未能解决你的问题,请参考以下文章
10分钟,手把手教学正确还原京东倒计时,初学者必看,简单易懂!