Create your own Mini Player
In this tutorial, we will explain how to create your own mini player on your iOS project.

Our goal here is to create a Mini Player like below by yourself, it will be a code base to allow you to set create a custom Mini Player.
We can describe the player as follows :
  • On the top, a progress bar to display the current STTrack progression
  • On the left, the image of the current STTrack
  • The first line is the title of the current STTrack
  • The second line is the title of the current STContent
  • On the right, the main button to control the STPlayer

To redo the design, we have to first create our custom UIView by adding a XIB file with his implementation:
  • MiniPlayer.xib
  • MiniPlayer.swift
Within the XIB, we have to add those elements:
We should map the IBOutlets with our MiniPlayer.swift file:
MiniPlayer.swift
import UIKit
final class MiniPlayer: UIView {
@IBOutlet private weak var imageView: UIImageView!
@IBOutlet private weak var progressView: UIProgressView!
@IBOutlet private weak var titleLabel: UILabel!
@IBOutlet private weak var subtitleLabel: UILabel!
@IBOutlet private weak var playButton: UIButton!
@IBOutlet private weak var pauseButton: UIButton!
@IBOutlet private weak var openExpandButton: UIButton!
}
Now we have to map the user interactions with our implementation:
MiniPlayer.swift
@IBAction private func didTapPlay(_ sender: Any) {
}
@IBAction private func didTapPause(_ sender: Any) {
}
@IBAction private func didTapOpenMainPage(_ sender: Any) {
}

Now that we have a complete UIView, we need to connect the elements with the SDK values.

Let's start by adding the STPlayer feature within our view by folloing those points:
  • Import the SDK
  • Observing the STPlayer changes
MiniPlayer.swift
import UIKit
import StayTunedSDK
final class MiniPlayer: UIView {
private var player: STPlayer? = STPlayer.shared
@IBOutlet private weak var imageView: UIImageView!
@IBOutlet private weak var progressView: UIProgressView!
@IBOutlet private weak var titleLabel: UILabel!
@IBOutlet private weak var subtitleLabel: UILabel!
@IBOutlet private weak var playButton: UIButton!
@IBOutlet private weak var pauseButton: UIButton!
@IBOutlet private weak var openExpandButton: UIButton!
override func awakeFromNib() {
self.player?.add(observer: self)
}
}
extension MiniPlayer: STPlayerObserver {
func playerCurrentTrackDidChange(to track: STTrack) {
}
func playerCurrentContentDidChange(to content: STContent) {
}
func playerCurrentTimeDidChange(to value: Double) {
}
func playerStateDidChange(to state: STPlayerState) {
}
}

We are going to set the image of the track, the title and subtitle of the view by observing the changes of a track or a content:
MiniPlayer.swift
extension MiniPlayer: STPlayerObserver {
private func setCurrentMedia() {
guard let track = self.player.currentTrack,
let content = self.player.currentContent else {
return
}
guard let imageUrl = URL(string: track.imgSrc ?? ""),
let imageData = try? Data(contentsOf: imageUrl) else {
return
}
self.imageView.image = UIImage(data: imageData)
self.titleLabel.text = track.title
self.subtitleLabel.text = content.title
}
// The track of the player did change
func playerCurrentTrackDidChange(to track: STTrack) {
self.setCurrentMedia()
}
// The content of the player did change
func playerCurrentContentDidChange(to content: STContent) {
self.setCurrentMedia()
}
}
We also need to listen to the playhead of the listening track to populate our progress view:
MiniPlayer.swift
extension MiniPlayer: STPlayerObserver {
func playerCurrentTimeDidChange(to value: Double) {
guard let time = self.player.currentTime,
let duration = self.player.getAudioDuration() else {
return
}
let progression = Float(time) / Float(duration)
self.progressView.setProgress(progression, animated: false)
}
}
Now we have to manage our Play and Pause button by observing the state of the player:
MiniPlayer.swift
extension MiniPlayer: STPlayerObserver {
private func setPlayingButton(hidden: Bool) {
self.playButton.isHidden = hidden
self.pauseButton.isHidden = !hidden
}
func playerStateDidChange(to state: STPlayerState) {
switch state {
case .playing, loading:
self.setPlayingButton(hidden: false)
case .paused:
self.setPlayingButton(hidden: true)
@unknown default:
fatalError()
}
}
}

We want to allow our user to press Play or Pause a track or to open the expand if he taps on the Mini Player. To send those interactions we have to implement our IBAction like this:
MiniPlayer.swift
@IBAction private func didTapPlay(_ sender: Any) {
self.player.resume()
}
@IBAction private func didTapPause(_ sender: Any) {
self.player.stop()
}
@IBAction private func didTapOpenMainPage(_ sender: Any) {
if let parentController = next as? UIViewController {
STExpand.shared?.present(from: parentController)
}
}

You can retrieve all the codes from our demo app: https://github.com/StayTunedAds/staytuned-ios-sdk
The Mini Player has been implemented by using the Clean Swift (VIP) architecture in the demo app. More information are available here: https://clean-swift.com
Copy link
On this page
Goal
Set up the UI
Connect to the SDK
Implement STPlayer feature
Retrieve all information needed
Send user interactions to the STPlayer
Resources