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.swiftimport UIKitfinal 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.swiftimport UIKitimport StayTunedSDKfinal 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.swiftextension 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.titleself.subtitleLabel.text = content.title}// The track of the player did changefunc playerCurrentTrackDidChange(to track: STTrack) {self.setCurrentMedia()}// The content of the player did changefunc playerCurrentContentDidChange(to content: STContent) {self.setCurrentMedia()}}
We also need to listen to the playhead of the listening track to populate our progress view:
MiniPlayer.swiftextension 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.swiftextension MiniPlayer: STPlayerObserver {private func setPlayingButton(hidden: Bool) {self.playButton.isHidden = hiddenself.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
Mini Player implementation: https://github.com/StayTunedAds/staytuned-ios-sdk/tree/master/SDKDemoApp/SDKDemoApp/Views/MiniPlayer
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