Adding Playback Slider to AVPlayer In Swift

In this tutorial, you will learn how to add a playback slider to AVPlayer in Swift to control audio playback.

By the end of this tutorial, you will have a working Swift code example that you can use in your mobile application.

Step 1: Create AVPlayer and AVPlayerItem

First, you need to import the necessary frameworks UIKit and AVFoundation, which provides the classes and methods necessary to work with audio and video content.

import UIKit
import AVFoundation

Next, define two member variables: AVPlayer and AVPlayerItemAVPlayer is the class that you use to control the playback of audio and video content while AVPlayerItem represents the audio or video data that you want to play.

var player: AVPlayer?
var playerItem: AVPlayerItem?

You can initialize the AVPlayer and AVPlayerItem in the viewWillAppear method of your view controller. This is where you set the URL of the audio file you want to play and create the AVPlayer instance.

If you are looking for SwiftUI code, then you can learn how to use AVPlayer and AVPlayeItem classes using both UIKit and SwiftUI in this tutorial: Play Music MP3 File From a Remote URL In Swift.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    
    let url = URL(string: "https://s3.amazonaws.com/kargopolov/kukushka.mp3")
    let playerItem: AVPlayerItem = AVPlayerItem(url: url!)
    player = AVPlayer(playerItem: playerItem)
}

Step 2: Create UIButton Programmatically

To create a play button programmatically, you first need to create an instance of UIButton and then configure its properties. You can set the button’s frame, background color, title, and add a target-action method that will be called when the button is tapped.

playButton = UIButton(type: UIButton.ButtonType.system) as UIButton
let buttonWidth: CGFloat =  150
let buttonHeight: CGFloat =  45
playButton!.frame = CGRect(x:  50, y:  100, width: buttonWidth, height: buttonHeight)
playButton!.backgroundColor = UIColor.lightGray
playButton!.setTitle("Play", for: UIControl.State.normal)
playButton!.tintColor = UIColor.black
playButton!.addTarget(self, action: #selector(self.playButtonTapped(_:)), for: .touchUpInside)
self.view.addSubview(playButton!)

Step 3: Create AVPlayerLayer and Add it as a Subview

The AVPlayerLayer is a layer that you add to your view hierarchy to display the video content of an AVPlayer instance. You create an instance of AVPlayerLayer, set its frame, and add it as a sublayer of your view’s layer.

let playerLayer = AVPlayerLayer(player: player!)
playerLayer.frame = CGRect(x:  0, y:  0, width:  10, height:  50)
self.view.layer.addSublayer(playerLayer)

Step 4: Handle Play Button Action to Pause and Play Music

You’ve already added a target-action method to the play button in the previous step. Now, you need to implement this method to handle the button tap. When the button is tapped, you check if the player is currently playing. If it is, you pause the player; otherwise, you play the player.

@objc func playButtonTapped(_ sender: UIButton) {
    if player?.rate ==  0 {
        player!.play()
        playButton!.setTitle("Pause", for: UIControl.State.normal)
    } else {
        player!.pause()
        playButton!.setTitle("Play", for: UIControl.State.normal)
    }
}

Step 5: Playback Slider. Add UISlider as a Subview

As a playback slider, you can use the UISlider component.

To create a UISlider programmatically, set its frame and properties, and add it to your view’s subviews. The UISlider is used to display the progress of the audio playback and to allow the user to seek to a different position in the audio.

let playbackSlider = UISlider(frame: CGRect(x:  10, y:  300, width:  300, height:  20))
playbackSlider.minimumValue =  0
self.view.addSubview(playbackSlider)

Step 6: Handle UISlider Value Changed Event

To handle the slider’s value change, you add a target-action method to the slider. This method will be called when the slider’s value changes, and you can use it to seek to the new position in the audio.

playbackSlider.addTarget(self, action: #selector(self.playbackSliderValueChanged(_:)), for: .valueChanged)

@objc func playbackSliderValueChanged(_ playbackSlider: UISlider) {
    let seconds: Int64 = Int64(playbackSlider.value)
    let targetTime: CMTime = CMTimeMake(value: seconds, timescale:  1)
    player!.seek(to: targetTime)
    
    if player!.rate ==  0 {
        player?.play()
    }
}

Step 7: Determine Music File Duration in Seconds

To set the maximum value of the slider, you need to determine the duration of the audio file in seconds. You can get the duration from the asset property of the AVPlayerItem.

let duration: CMTime = playerItem.asset.duration
let seconds: Float64 = CMTimeGetSeconds(duration)
playbackSlider.maximumValue = Float(seconds)

Step 8: Update UISlider When mp3 is Playing

To keep the slider’s value in sync with the playback progress, you add a periodic time observer to the player. This observer will be called at regular intervals, and you can use it to update the slider’s value.

var timer: Any?
timer = player?.addPeriodicTimeObserver(forInterval: CMTimeMake(value:  1, timescale:  600), queue: DispatchQueue.main) { [weak self] time in
    guard self != nil else { return }
    let currentTime = CMTimeGetSeconds(time)
    playbackSlider.value = Float(currentTime)
}

Playback Slider: Complete Code Example

Below is a complete code example in Swift that demonstrates how to add a playback slider to AVPlayer. You can try it and use it in your app to play music or video.

import UIKit
import AVFoundation

class ViewController: UIViewController  {
    
    var player: AVPlayer?
    var playerItem: AVPlayerItem?
    var playButton: UIButton?
    var duration: CMTime?
    var timer: Any?
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        let url = URL(string: "https://s3.amazonaws.com/kargopolov/kukushka.mp3")
        let playerItem:AVPlayerItem = AVPlayerItem(url: url!)
        player = AVPlayer(playerItem: playerItem)
        
        let playerLayer=AVPlayerLayer(player: player!)
        playerLayer.frame=CGRect(x:0, y:0, width:10, height:50)
        self.view.layer.addSublayer(playerLayer)
        
        playButton = UIButton(type: UIButton.ButtonType.system) as UIButton
        let xPostion:CGFloat = 50
        let yPostion:CGFloat = 100
        let buttonWidth:CGFloat = 150
        let buttonHeight:CGFloat = 45
        
        playButton!.frame = CGRect(x:xPostion, y:yPostion, width:buttonWidth, height:buttonHeight)
        playButton!.center = CGPoint(x: self.view.bounds.midX, y: self.view.bounds.midY)
        playButton!.backgroundColor = UIColor.lightGray
        playButton!.setTitle("Play", for: UIControl.State.normal)
        playButton!.tintColor = UIColor.black
        playButton!.addTarget(self, action: #selector(self.playButtonTapped(_:)), for: .touchUpInside)
        
        self.view.addSubview(playButton!)
        
        
        // Add playback slider
        
        let playbackSlider = UISlider(frame:CGRect(x:10, y:300, width:300, height:20))
        playbackSlider.center = CGPoint(x: self.view.bounds.midX, y: self.view.bounds.midY +  50)
        playbackSlider.minimumValue = 0
        
        
        let duration : CMTime = playerItem.asset.duration
        let seconds : Float64 = CMTimeGetSeconds(duration)
        
        playbackSlider.maximumValue = Float(seconds)
        playbackSlider.isContinuous = true
        playbackSlider.tintColor = UIColor.green
        
        playbackSlider.addTarget(self, action: #selector(self.playbackSliderValueChanged(_:)), for: .valueChanged)
        
        // Set up the periodic time observer
        timer = player?.addPeriodicTimeObserver(forInterval: CMTimeMake(value:  1, timescale:  600), queue: DispatchQueue.main) { [weak self] time in
            guard self != nil else { return }
            let currentTime = CMTimeGetSeconds(time)
            playbackSlider.value = Float(currentTime)
        }
        
        self.view.addSubview(playbackSlider)
        
    }
    
    @objc func playbackSliderValueChanged(_ playbackSlider:UISlider)
    {
        
        let seconds : Int64 = Int64(playbackSlider.value)
        let targetTime:CMTime = CMTimeMake(value: seconds, timescale: 1)
        
        player!.seek(to: targetTime)
        
        if player!.rate == 0
        {
            player?.play()
        }
    }
    
    
    @objc func playButtonTapped(_ sender:UIButton)
    {
        if player?.rate == 0
        {
            player!.play()
            playButton!.setTitle("Pause", for: UIControl.State.normal)
        } else {
            player!.pause()
            playButton!.setTitle("Play", for: UIControl.State.normal)
        }
    }
    
    // Remember to remove the observer when the view disappears
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        if let timer = timer {
            player?.removeTimeObserver(timer)
        }
    }
    
}

Add Playback Slider to AVPlayer In Swift

Conclusion

I hope this tutorial was helpful to you and you were able to successfully add a playback slider to AVPlayer in your mobile application.

For more Swift code examples and tutorials, please check the Swift Code Examples page on this website.

Happy learning!

Leave a Reply

Your email address will not be published. Required fields are marked *