SwiftUIを利用したミュージックアプリのUI再現
本記事では、SwiftUIを用いた “ミュージック” アプリUIの実装と、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を調整する必要があります。
PlayerTabView
の.background()
にGeometryReader
をかませて、Tabのサイズを取得します。.background()
をの中に入れる理由は、カスタムタブ全体をGeometryReader
で覆うとサイズがデバイスいっぱいに広がってしまうためです。
取得したサイズを、.preference()
を利用して通知します。
ScrollViewにはcontentInsetを調整するmodifierがないので、TabBarの高さ分のpaddingを挿入して対応します。
シークバーの再現
再生位置の表示・操作を行うシークバーは、本物と少しデザインが異なりますがSliderを用いて実装しました。@State
を利用することで、簡単にリアクティブな表示ができます。
完成物
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で実装可能な仕組みに変えることで、綺麗な設計に保つことができるとも言えます。