SwiftUIを利用したミュージックアプリのUI再現

Satsuki Hashiba
Eureka Engineering
Published in
6 min readJul 20, 2020

本記事では、SwiftUIを用いた “ミュージック” アプリUIの実装と、SwiftUIを用いてアプリ開発を行った場合の利点と課題を考察します。

Photo by Travis Yewell on Unsplash

再生中バーの実装

タブの上にあり、再生中の曲が表示されているバーを指します。タップでプレイヤーの画面がモーダルで表示されます。

SwiftUIで再現した再生中バー

今回は再生中バーを含むカスタムタブを実装し、ZStackでViewの上に重ねています。

Tabのselected表示は、@Bindingを用いて連動させます。

背景のBlurは、UIViewRepresentableプロトコルでUIVisualEffectViewを用いて実装しています。

はじめはデフォルトのTabViewを実装し、その上にoverlayでNowPlayingViewを重ねる方法を取っていましたが、以下の2つの理由から上記の実装に変更しました。

  • TabViewからTabの高さを取得できないので、NowPlayingViewのpaddingに定数を指定しなければならない
  • TabとNowPlayingViewが別のViewになるので、背景のblurが繋がらない

ScrollViewのInset調整

カスタムのTabを実装したので、下にあるViewのコンテンツに被らないようにScrollViewのInsetを調整する必要があります。

Inset調整がされていないので、コンテンツがタブと被ってしまうScrollView

PlayerTabView.background()GeometryReaderをかませて、Tabのサイズを取得します。.background()をの中に入れる理由は、カスタムタブ全体をGeometryReaderで覆うとサイズがデバイスいっぱいに広がってしまうためです。

取得したサイズを、.preference()を利用して通知します。

ScrollViewにはcontentInsetを調整するmodifierがないので、TabBarの高さ分のpaddingを挿入して対応します。

シークバーの再現

再生位置の表示・操作を行うシークバーは、本物と少しデザインが異なりますがSliderを用いて実装しました。@Stateを利用することで、簡単にリアクティブな表示ができます。

再生位置のシークバー 両側の数字がシークポジションに対応している

完成物

コード: shiba1014/Music_SwiftUI

ライブラリ画面
プレイヤー画面 再生ボタンもbindingされている
タブの切り替え

SwiftUIを使う利点

UIとStateの同期が自動で行われる

変数に対してStateやBindingといった属性をつけることで、変数が変更された時には自動的にUIが更新され、UIによる変更は自動的に変数に反映されます。これにより、データとUIの不整合が発生しづらくなります。

アニメーションが手軽に実装できる

withAnimation()で非常に簡単にアニメーションを記述できます。また、.matchedGeometryEffectを利用することでkeynoteのマジックムーブのような、同じオブジェクトが繋がったアニメーションを行うこともできます。

TableView / CollectionViewの実装がシンプルになる

SwiftUIを用いることでどの部品も簡潔に書くことができますが、特にTableViewおよびCollectionViewの容易さは顕著です。delegateやdataStoreが必要もなく、Rowの中身やタップした際の挙動を同じ箇所にまとめて書くことができます。

SwiftUIが持つ課題

UIのカスタマイズが限定的

例えばSliderでは、thumbnailの画像を変更することができません。Modifierが用意されていないカスタマイズをしようと思うと、UIViewを利用したり、今回のPlayerTabViewのように見た目や挙動をゼロから作ったりする必要があります。デフォルトに忠実なデザインであれば問題ありませんが、そうでない場合はコーディングの負担が増えてしまいます。

Programmaticallyな操作が困難

それぞれの部品はViewプロトコルに隠蔽されているため、TabViewの高さを取得したり、ScrollViewのOffsetを取得したりすることが困難になります。また、ScrollViewを任意の箇所にスクロールさせるなどの操作も容易ではありません。

一方で、このような問題をハックして無理に解決せず、SwiftUIで実装可能な仕組みに変えることで、綺麗な設計に保つことができるとも言えます。

--

--