🚀

SwiftUIで自動無限スクロールを実現する

2025/02/10に公開

はじめに

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秒の遅延を入れてスクロールを完了させてから自動無限スクロールのアニメーションを開始しています。
アニメーションの仕組みは先ほどと変わりませんが、initialOffsettotalWidth を足した分スクロールさせることで丁度Item一覧の1スクロール分でループするように指定しています。

        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
            withAnimation(.linear(duration: 15).repeatForever(autoreverses: false)) {
                scrollOffset = initialOffset + totalWidth
            }
        }

実行

ということで下記の動きが実現できました。

下記でもコードの全容を公開してますので合わせてご覧ください

https://github.com/entaku0818/samplePlayGround/blob/main/samplePlayGround/samplePlayGround/InfiniteScrollView.swift

Discussion