HI!
I am trying to create a basic music app and I am using AVAudioPlayer to play the songs. I have a slider that I am using to seek through the song that's playing, and it's working in that fashion. However, what I am having trouble with is getting the slider to update in real time along with the song that's playing. So when a song starts to play, the slider should start updating as well and continue to do so until the song ends. Currently, the slider doesn't even move at all unless I drag, in which case it will work and update as you'd expect.
I set the slider's maximum value, and I also set it to be continous.
I use a timer inside this method, to get the slider to update in real time and reflect song time continuously.
@objc func seekSliderChanged(_ slider: UISlider) {
let duration = player!.duration
slider.maximumValue = Float(duration)
let time = duration/duration
//seeking through current gabay
player!.currentTime = TimeInterval(slider.value)
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: {[weak self]
_ in
if let weakSelf = self {
slider.value = Float(weakSelf.player!.currentTime)
}
})
}
here's the slider properties being set.
```
//seek through sider
seekSlider = UISlider()
seekSlider.isContinuous = true
seekSlider.maximumValue = Float(player!.duration)
seekSlider.isUserInteractionEnabled = true
seekSlider.translatesAutoresizingMaskIntoConstraints = false
seekSlider.thumbTintColor = UIColor.clear
// seekSlider.setThumbImage(UIImage(named: "thumb"), for: .normal)
seekSlider.addTarget(self, action: #selector(seekSliderChanged), for: .valueChanged)
holder.addSubview(seekSlider)
```
and here's the whole code
```
//
/ / PLayerViewController.swift
// Maanso
//
//
import UIKit
import AVFoundation
class PLayerViewController: UIViewController, AVAudioPlayerDelegate {
//seek through sider
var seekSlider: UISlider!
@IBOutlet var holder: UIView!
var Git = UILabel()
var gabayArray = [Gabays]()
var currentIndex = 0
var position: Int = 0
var player: AVAudioPlayer?
//user interface elements
var coverImageView: UIImageView!
var gabayName: UILabel!
var gabyaaName: UILabel!
//buttons
var playPauseButton: UIButton!
var backButton: UIButton!
var forwardButton: UIButton!
var timer: Timer!
override func viewDidLoad() {
super.viewDidLoad()
configure()
player!.delegate = self
// configureUI()
}
override func viewWillAppear(_ animated: Bool) {
if let player = player {
// player.play()
player.prepareToPlay()
}
}
override func viewDidLayoutSubviews() {
if holder.subviews.count == 0 {
configure()
}
}
func configure() {
//set up player
let gabay = gabayArray[position]
let urlString = Bundle.main.path(forResource: gabay.gabayName, ofType: "mp3")
do {
try AVAudioSession.sharedInstance().setMode(.default)
try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
guard let urlString = urlString else{return}
player = try AVAudioPlayer(contentsOf: URL(string: urlString)!)
guard let player = player else{return}
player.volume = 0.5
player.delegate = self
player.play()
}
catch{
print("error is: \(error.localizedDescription)")
}
configureUI()
}
//MARK: - actions
@objc func volumeSliderChanged(_ slider: UISlider) {
let value = slider.value
//adjust player volume
guard let player = player else{return}
player.volume = value
}
@objc func playPauseButtonTapped(_ slider: UISlider) {
guard let player = player else{return}
if player.isPlaying {
player.stop()
playPauseButton.setBackgroundImage(UIImage(systemName: "play.fill"), for: .normal)
}else{
player.play()
playPauseButton.setBackgroundImage(UIImage(systemName: "pause.fill"), for: .normal)
}
}
@objc func backButtonTapped() {
if position > 0
{
position = position - 1
player!.stop()
for subview in holder.subviews {
subview.removeFromSuperview()
}
configure()
// configureUI()
}
}
@objc func forwardButtonTapped() {
if position < gabayArray.count - 1{
position = position + 1
player!.stop()
for subview in holder.subviews {
subview.removeFromSuperview()
}
configure()
// configureUI()
}
}
@objc func seekSliderChanged(_ slider: UISlider) {
let duration = player!.duration
slider.maximumValue = Float(duration)
let time = duration/duration
//seeking through current gabay
player!.currentTime = TimeInterval(slider.value)
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: {[weak self]
_ in
if let weakSelf = self {
slider.value = Float(weakSelf.player!.currentTime)
}
})
}
public func configureUI() {
//set up user interface
let gabay = gabayArray[position]
//set up imagecoverview
coverImageView = UIImageView()
coverImageView.contentMode = .scaleAspectFill
coverImageView.image = UIImage(named: gabay.imageName)
coverImageView.translatesAutoresizingMaskIntoConstraints = false
holder.addSubview(coverImageView)
//set up the two labels
gabayName = UILabel()
gabayName.textAlignment = .center
gabayName.numberOfLines = 0
gabayName.translatesAutoresizingMaskIntoConstraints = false
gabayName.text = gabay.gabayName
gabayName.font = UIFont(name: "helvetica", size: 20)
holder.addSubview(gabayName)
gabyaaName = UILabel()
gabyaaName.translatesAutoresizingMaskIntoConstraints = false
gabyaaName.text = gabay.gabyaaName
gabyaaName.font = UIFont(name: "helvetica", size: 18)
gabyaaName.textAlignment = .center
gabyaaName.numberOfLines = 0
holder.addSubview(gabyaaName)
//set up sliders.
let volumeSlider = UISlider()
volumeSlider.value = 0.5
volumeSlider.translatesAutoresizingMaskIntoConstraints = false
volumeSlider.addTarget(self, action: #selector(volumeSliderChanged), for: .valueChanged)
volumeSlider.layer.cornerRadius = 8
volumeSlider.isUserInteractionEnabled = true
holder.addSubview(volumeSlider)
//seek through sider
seekSlider = UISlider()
seekSlider.isContinuous = true
seekSlider.maximumValue = Float(player!.duration)
seekSlider.isUserInteractionEnabled = true
seekSlider.translatesAutoresizingMaskIntoConstraints = false
seekSlider.thumbTintColor = UIColor.clear
// seekSlider.setThumbImage(UIImage(named: "thumb"), for: .normal)
seekSlider.addTarget(self, action: #selector(seekSliderChanged), for: .valueChanged)
holder.addSubview(seekSlider)
//set up buttons, play button
playPauseButton = UIButton()
playPauseButton.tintColor = .black
playPauseButton.setBackgroundImage(UIImage(systemName: "pause.fill"), for: .normal)
playPauseButton.translatesAutoresizingMaskIntoConstraints = false
playPauseButton.addTarget(self, action: #selector(playPauseButtonTapped), for: .touchUpInside)
holder.addSubview(playPauseButton)
//back button
backButton = UIButton()
backButton.tintColor = .black
backButton.setBackgroundImage(UIImage(systemName: "backward.fill"), for: .normal)
backButton.translatesAutoresizingMaskIntoConstraints = false
backButton.addTarget(self, action: #selector(backButtonTapped), for: .touchUpInside)
holder.addSubview(backButton)
//forward button
forwardButton = UIButton()
forwardButton.tintColor = .black
forwardButton.setBackgroundImage(UIImage(systemName: "forward.fill"), for: .normal)
forwardButton.translatesAutoresizingMaskIntoConstraints = false
forwardButton.addTarget(self, action: #selector(forwardButtonTapped), for: .touchUpInside)
holder.addSubview(forwardButton)
//volume buttons
let rightVolButton = UIButton()
rightVolButton.translatesAutoresizingMaskIntoConstraints = false
rightVolButton.setBackgroundImage(UIImage(systemName: "volume.3.fill"), for: .normal)
holder.addSubview(rightVolButton)
//set up constraints
NSLayoutConstraint.activate([
coverImageView.topAnchor.constraint(equalTo: holder.layoutMarginsGuide.topAnchor, constant: 80),
coverImageView.leadingAnchor.constraint(equalTo: holder.layoutMarginsGuide.leadingAnchor, constant: 0),
coverImageView.trailingAnchor.constraint(equalTo: holder.layoutMarginsGuide.trailingAnchor, constant: 0),
gabayName.topAnchor.constraint(equalTo: coverImageView.bottomAnchor, constant: 100),
gabayName.centerXAnchor.constraint(equalTo: holder.centerXAnchor),
gabyaaName.topAnchor.constraint(equalTo: gabayName.bottomAnchor, constant: 15),
gabyaaName.centerXAnchor.constraint(equalTo: holder.centerXAnchor),
//seek slider
seekSlider.topAnchor.constraint(equalTo: gabyaaName.topAnchor, constant: 30),
seekSlider.centerXAnchor.constraint(equalTo: holder.centerXAnchor),
seekSlider.widthAnchor.constraint(equalTo: holder.widthAnchor, multiplier: 0.8),
//buttons
playPauseButton.topAnchor.constraint(equalTo: seekSlider.bottomAnchor, constant: 25),
playPauseButton.centerXAnchor.constraint(equalTo: holder.centerXAnchor),
playPauseButton.widthAnchor.constraint(equalToConstant: 70),
playPauseButton.heightAnchor.constraint(equalToConstant: 70),
backButton.topAnchor.constraint(equalTo: seekSlider.bottomAnchor, constant: 25),
backButton.leadingAnchor.constraint(equalTo: holder.leadingAnchor, constant: 20),
backButton.widthAnchor.constraint(equalToConstant: 70),
backButton.heightAnchor.constraint(equalToConstant: 70),
forwardButton.topAnchor.constraint(equalTo: seekSlider.bottomAnchor, constant: 25),
forwardButton.trailingAnchor.constraint(equalTo: holder.trailingAnchor, constant: -20),
forwardButton.widthAnchor.constraint(equalToConstant: 70),
forwardButton.heightAnchor.constraint(equalToConstant: 70),
//volume slider
volumeSlider.topAnchor.constraint(equalTo: playPauseButton.bottomAnchor, constant: 30),
volumeSlider.centerXAnchor.constraint(equalTo: holder.centerXAnchor),
volumeSlider.widthAnchor.constraint(equalTo: holder.widthAnchor, multiplier: 0.8),
rightVolButton.topAnchor.constraint(equalTo: playPauseButton.bottomAnchor, constant: 35),
rightVolButton.trailingAnchor.constraint(equalTo: holder.layoutMarginsGuide.trailingAnchor, constant: 0),
])
}
//MARK: - AVAudioplayer delegate
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
if flag, position < gabayArray.count - 1 {
position = position + 1
for subview in holder.subviews{
subview.removeFromSuperview()
}
configure()
}
else{
position = 0
for subview in holder.subviews{
subview.removeFromSuperview()
}
configure()
}
}
override func viewWillDisappear(_ animated: Bool) {
player?.stop()
}
}
```