SwiftUIを使ってMusicPlayerのSeekBarを作ってみた

使用したプロジェクト

概要


MusicPlayerのSeekBarには主に2つの機能があります。1つ目は再生されている楽曲の再生位置を知らせること、2つ目は現在の再生位置からSeekBarをスライドした際に楽曲にスライドした位置を伝えることです。 今回はこの機能を満たすことを目標に実装します。

実装

SeekBarの雛形を作る

Stateに再生時間のTimeIntervalを持ったSliderのラッパービューを実装します。


ちなみにaccentColorを指定するとSliderのleft borderがaccentColorになります。

現在の再生位置を表示する

現在の再生位置を知らせる方法として、ラベルで再生した秒数、終了時までのカウントダウンを表示することに加え、SliderのThumbの位置で表現することができます。

Viewの実装に入る前に便利なUtilityを用意しようと思います。MediaPlayerの再生時間などはTimeIntervalで表現されているので、CalendarにTimeIntervalをStringに変換するExtensionを用意します。


TimeInterval(Double)に実装しても良かったのですが、時間の加工などはCalendarに書くようにしているので今回はCalendarに実装しました。ここら辺は好みだと思います。

ではこのUtilityを使って、再生した時間、終了時までのカウントダウンを表示していきます。

SliderのInitializerにはminimumValueLabelとmaximumValueLabelが用意されており、特に左右のラベル表示位置にこだわりはないのでこちらを使用します。 Initializerに使用するMusicPlayerControllerを受け取って再生情報を使用します。


しかしこのままではSwiftUI側にPlayerの再生時間が変更されたことが通知されないので、最初の一回のみレンダリングされます。そこでTimerを使用してSliderに定期的にイベントを送信します。UIViewControllerを使っていた際はTimer.scheduledTimerこちらを使っていましたが、SwiftUIで使用する場合は非常に面倒臭いです。そこで、SwiftUIのViewに用意されているonReceiveメソッドとTimer側で用意されているPublisherを作成するpublishメソッドを使用してSliderにイベントを流します


1秒間隔でSliderにイベントを流すことができました。

SeekBarをスライドさせて時にMusicPlayerControllerに伝達する

スライダーにイベントを流し込み、再生情報を表示することができました。しかしこのままでは表示はできてもユーザーから変更することはできません。そこでSeekBarにisEdittingステートを用意して変更状態を管理します。

SliderのInitializerにはonEditingChangedが用意されていて編集時のハンドリングを行うことができます。 それに加て、先ほど追加したTimerのイベントにisEditingを考慮した実装に変更します。


以上の実装によって、ユーザーのアクションと競合しない形でSliderにイベントを流すことができました。

まとめ

今回使用したonReceiveなどSwiftUIには便利なメソッドが数多く用意されていて意外と簡単に実装できたので、いろいろなプロジェクトでSwiftUIを活用した実装ができないか試してみようと思います。

プロフィール

てらにゃん

19歳学生。よく書くプログラミング言語はSwift, Typescript。業務委託のお仕事はお断りさせていただいています。インターン、アルバイトのお誘いは大歓迎です!

Contact me

Twitter: @tera_ny
Github: @g4zeru