Search code examples
iosswiftslideravaudioplayercore-audio

swift 3: How to add UISlider?


I have ViewController with AVAudioPlayer. Now I have this code

import UIKit
import AVFoundation

var audioPlayer = AVAudioPlayer()

class ViewController: UIViewController {

@IBOutlet weak var slider: UISlider!
@IBOutlet weak var playButton: UIButton!
var index = 0
var timer: Timer?

override func viewDidLoad() {
    super.viewDidLoad()

    if index == 0{

       let url = Bundle.main.url(forResource: "1", withExtension: "mp3")!

        do {
            audioPlayer = try AVAudioPlayer(contentsOf: url)
            audioPlayer.prepareToPlay()
            //audioPlayer.play()
            //play(sender:AnyObject.self as AnyObject)

        } catch let error {
            print(error.localizedDescription)
        }
    }
}

@IBAction func slide(_ slider: UISlider) {
    audioPlayer.currentTime = TimeInterval(slider.value)
}

@IBAction func play(sender: AnyObject) {
    if !audioPlayer.isPlaying{
        audioPlayer.play()
        // **** The line below is the new line ****
        timer = Timer(timeInterval: 1.0, target: self, selector: #selector(self.updateSlider), userInfo: nil, repeats: true)
        RunLoop.main.add(timer!, forMode: .commonModes)
    } else {
        audioPlayer.pause()
        playButton.setImage(UIImage(named: "pause.png"), for: UIControlState.normal)
        timer?.invalidate()
    }
}

func updateSlider(_ timer: Timer) {
    slider.value = Float(audioPlayer.currentTime)
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}
}

I want to add UISlider that change scrub through the audio file. How to do it?


Solution

  • First, you have to add a new IBAction from the slider to make sure your class gets notified when the sliders value changes (Look for "Responding to User Interaction" here: https://developer.apple.com/reference/uikit/uislider#2557863)

    In this event handler you have to set the audios current time

    @IBAction func slide(_ slider: UISlider) {
        audioPlayer.currentTime = TimeInterval(slider.value)
    }
    

    To make sure the slider updates its value according to the current time, you have to add a timer when you start the player that calls a custom method which updates the sliders value.

    @IBAction func play(sender: AnyObject) {
        if !audioPlayer.isPlaying{
            audioPlayer.play()
            // **** The line below is the new line ****
            timer = Timer(timeInterval: 1.0, target: self, selector: #selector(self.updateSlider), userInfo: nil, repeats: true)
            RunLoop.main.add(timer, forMode: .commonModes)
        } else {
            audioPlayer.pause()
            playButton.setImage(UIImage(named: "pause.png"), for: UIControlState.normal)
            timer.invalidate()
        }
    }
    

    Afterwards you have to create the method which updates the sliders value

    func updateSlider(_ timer: Timer) {
        slider.value = Float(audioPlayer.currentTime)
    }
    

    Then you have to set the sliders maximum value

    override func viewDidLoad() {
        super.viewDidLoad()
    
        if index == 0{
    
           let url = Bundle.main.url(forResource: "1", withExtension: "mp3")!
    
            do {
                audioPlayer = try AVAudioPlayer(contentsOf: url)
                audioPlayer.prepareToPlay()
                // **** These two lines below are new ****
                slider.maximumValue = Float(audioPlayer.duration)
                slider.value = 0.0
            } catch let error {
                print(error.localizedDescription)
            }
        }
    }
    

    And finally you have to create a property below your IBOutlets which holds the timer

    var timer: Timer?