🚀
SwiftUIで自動無限スクロールを実現する
はじめに
SwiftUIで自動無限スクロールの処理が必要だったので作成してみました。
自動無限スクロールと言っても求められている仕様によって内容が変わると思います。今回の仕様は下記のようになっています
- 左右にどちらにも自動で無限にスクロールする
- 決められた個数の内容を繰り返し表示する。表示する内容は固定である。
左へ自動で無限にスクロールする
左へ向かうのは通常のスクロールと同じ動き方なので特段難しいことはないです。
下記のコードが動で無限にスクロールする処理の中心です。
.onAppear {
let totalWidth = CGFloat(items.count) * (itemWidth + spacing)
withAnimation(.linear(duration: 15).repeatForever(autoreverses: false)) {
scrollOffset = -totalWidth
}
}
自動スクロールとして見せたい範囲のスクロール幅を totalWidth
で指定しています。この値がスクロールの移動距離になりアニメーションの処理と合わせることで無限にスクロールするように見せかけています。
-
スクロール幅の計算
-
totalWidth
は1セット分のコンテンツ全体の幅 - アイテムの数 × (アイテムの幅 + 間隔) で計算
-
アニメーション処理を指定することで自動でスクロールさせています。アニメーションの処理は下記の通りです
-
アニメーションの設定
-
.linear
: 一定速度でのスクロールを実現 -
duration: 15
: 15秒かけて1セット分移動 -
repeatForever
: 永続的なアニメーション -
autoreverses: false
: 逆方向に戻らず、常に同じ方向に移動
-
右へ自動で無限にスクロールする
右へ向かうのは通常と逆のスクロール処理になりいわば戻るスクロールになるので少し複雑ですが工夫でそのように見せかけています。
.onAppear {
if isFirstAppear {
scrollOffset = initialOffset
isFirstAppear = false
let totalWidth = CGFloat(items.count) * (itemWidth + spacing)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
withAnimation(.linear(duration: 15).repeatForever(autoreverses: false)) {
scrollOffset = initialOffset + totalWidth
}
}
}
}
まずは最初のタイミングでItemの最後の位置まで scrollOffset
を指定することでスクロールさせています。
scrollOffset = initialOffset
その後、DispatchQueue.main.asyncAfterで0.1秒の遅延を入れてスクロールを完了させてから自動無限スクロールのアニメーションを開始しています。
アニメーションの仕組みは先ほどと変わりませんが、initialOffset
に totalWidth
を足した分スクロールさせることで丁度Item一覧の1スクロール分でループするように指定しています。
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
withAnimation(.linear(duration: 15).repeatForever(autoreverses: false)) {
scrollOffset = initialOffset + totalWidth
}
}
実行
ということで下記の動きが実現できました。
下記でもコードの全容を公開してますので合わせてご覧ください
Discussion