😊
(SwiftUI)ScrollViewで任意の座標にスクロールする
はじめに
以下の環境で動作確認しました。
- Xcode Version 14.2 (14C18)
- iOS 15.7.1
- 実機 iPhone 13
※iOS 14以上であれば同じ挙動になるはずですが、すべての環境で動作を保証するものではありません。
実装例
縦横が1000 x 1000のフレームを作成し、四隅にボタンを配置します。それぞれのボタンを押すと目的地の座標にスクロールします。
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
ScrollViewReader { proxy in
ScrollView([.horizontal, .vertical], showsIndicators: true) {
ZStack {
Button(action: {
withAnimation {
proxy.scrollTo(0, anchor: UnitPoint(x: 0.0, y: 1.0))
}
}) {
Text("左下に移動")
.frame(width: 250, height: 250)
.foregroundColor(.white)
.background(.indigo)
}
.offset(x: 0, y: 0)
Button(action: {
withAnimation {
proxy.scrollTo(0, anchor: UnitPoint(x: 1.0, y: 0.0))
}
}) {
Text("右上に移動")
.frame(width: 250, height: 250)
.foregroundColor(.white)
.background(.indigo)
}
.offset(x: 0, y: 750)
Button(action: {
withAnimation {
proxy.scrollTo(0, anchor: UnitPoint(x: 1.0, y: 1.0))
}
}) {
Text("右下に移動")
.frame(width: 250, height: 250)
.foregroundColor(.white)
.background(.indigo)
}
.offset(x: 750, y: 0)
Button(action: {
withAnimation {
proxy.scrollTo(0, anchor: UnitPoint(x: 0.0, y: 0.0))
}
}) {
Text("左上に移動")
.frame(width: 250, height: 250)
.foregroundColor(.white)
.background(.indigo)
}
.offset(x: 750, y: 750)
}
.frame(width: 1000, height: 1000, alignment: .topLeading)
.border(.blue, width: 10)
.id(0)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}
}
解説
実装の流れは以下のとおりです。
- ScrollViewReaderでScrollViewを囲みます。
- スクロール制御対象のビューに
.id()
でIDを設定します。 -
proxy.scrollTo(ビューのID, anchor: UnitPoint(x: 移動先のx座標, y: 移動先のy座標))
を実行して目的の場所にスクロールします。
ScrollViewReaderの中でビューを特定できればIDの値は何でも構いません。実装例ではid(0)
としました。
任意の座標にスクロールする場合はUnitPoint
で移動先の座標を指定します。座標は0.0から1.0に正規化されるので注意してください。左上が(x, y) = (0.0, 0.0)
、右下が(x, y) = (1.0, 1.0)
です。
実装例のフレームサイズは1000 x 1000ですから、例えばフレームの中心に移動したければUnitPoint(x: 0.5, y: 0.5)
を指定します。UnitPoint(x: 500.0, y: 500.0)
は間違いです。
Discussion