はじめに
こちらの記事は、アソビュー! Advent Calendar 2024の2日目(表面)です。
アソビューでiOSアプリ開発をしている上中です。
今回はiOSアプリでカルーセルを作る時に苦労した話をしたいと思います。
環境
- Xcode Version 16.0
- Swift 5
- Minimum Deployments: 16.0
やりたいことと課題
最近、アソビューのアプリのTOPに特集が表示されるようになりました。
見ての通り、いわゆるカルーセルのようなUIで作成しているのですが、思いの外苦労しました。
アソビューアプリはSwiftUIで実装されているのでSwiftUIで実現したいところです。
最初に思いついたのはTabViewなのですが、TabViewだと画像の両隣にある前画像と次画像の一部がチラ見えしている見切れ表示が実現できません。
また、ScrollViewで実現しようとすると、iOS16以下ではページングのように画像をめくる動作を実現できません。 (iOS17からできるようになったみたいです)
他のアプリでも似たようなUIは見かけたので、多分もっといいやり方はあるんだろうなぁ、、、と思いつつ、結局SwiftUIだけで作るのは諦めてUIkitの機能も使いつつなんとかしました。
誰かもっといい方法があれば教えていただけるとありがたいです。
実装
最終的に実装したのは以下のようなコンポーネントです。
まずはスクロールビューは以下になります。
UIScrollViewは、isPagingEnabledをtrueにすることでページングのような動きをしてくれますので、それを利用します。
UIHostingControllerを利用し、各ページの中身はSwiftUIで作って、UIScrollViewのSubViewに追加する形にします。
これだけだと画像の左右の見切れは実現できないので、それは次のコードで説明します。
イメージとしては、画面幅より小さい幅で作られた画像をHStackで横並びにすることで、隣の画像の一部が見えるという単純な仕組みです。
こちらのコードで先ほどのPagingScrollViewを利用してカルーセルを実現しています。
今回、見切れの幅と画像間の隙間は固定で8としています。
まず②で画像サイズを決めています。画像のサイズは画面幅から見切れ分x2と画像同士の隙間x2の幅を除いたサイズで動的に算出しています。
①で中身のframeを画像幅+隙間サイズ分で作り、画像をセンターに置いています。これで画像の左右に隙間ができます。
隙間については以下のようにHStackのspacingで指定しても問題ないです。(spacingは先頭にはスペースが入らないので、この場合はpaddingでleadingに隙間を入れる必要があります)。
あとはポイントとなるスクロール量の調整です。画面サイズ幅分スクロールしてしまうと、ページングした時に見切れ+画像の隙間分もスクロールしてしまうので、スクロールする度にセンターがずれていきます。
つまり①の幅分だけスクロールさせる必要があるため、PagingScrollViewのサイズを調整します。
③で画面幅まで広げたPagingScrollViewのframeに、見切れ片方分+画像隙間の半分のサイズのpaddingを左右に入れています。
これによって、UIScrollViewが①と同じサイズに調整され、このサイズがUIScrollViewのスクロール量になります。
この時、UIScrollViewのclipsToBoundsをfalseにしていることで、UIScrollViewのframeの外側にある見切れ部分も表示されます。
以上で以下のようなカルーセルが完成です。
まとめ
今回は見切れのあるカルーセルを作ってみました。
UIHostingControllerを初めて使ったのと、frameやpaddingの仕組みをちゃんと理解できていなかったためか、見切れのレイアウト調整や微妙なスクロール量の調整に手こずってしまいました。
おかげでレイアウトやUIHostingControllerを利用した開発の理解度が上がった気がします。
さいごに
アソビューでは、「生きるに、遊びを。」を実現するための良いプロダクトを世の中に届けられるよう共に挑戦していく様々なエンジニアを募集しています。 弊社のiOSアプリ開発に興味のある方もぜひ一度お話しできればと思います。
カジュアル面談のご希望も随時お受けしておりますので、お気軽にエントリーください! お待ちしております。