SwiftUI repeatForever と repeatCount
アニメーションを繰り返し実行したい場合、repeatForever や repeatCount を使う。ローディングインジケーターや注目を集めたい要素など、継続的な動きが必要な場面で活躍する。
repeatForever の基本
repeatForever() は、アニメーションを無限に繰り返す。
struct PulsingCircle: View {
@State private var isPulsing = false
var body: some View {
Circle()
.fill(.blue)
.frame(width: 100, height: 100)
.scaleEffect(isPulsing ? 1.2 : 1.0)
.opacity(isPulsing ? 0.6 : 1.0)
.animation(
.easeInOut(duration: 1.0).repeatForever(autoreverses: true),
value: isPulsing
)
.onAppear {
isPulsing = true
}
}
}onAppear で状態を変更し、repeatForever でその変更を永続的にアニメーションさせる。autoreverses: true により、終点に達したら始点に戻る動きを繰り返す。
autoreverses パラメータ
autoreverses は、アニメーションの終点から始点に戻るかどうかを制御する。
// 行って戻る(往復)
.repeatForever(autoreverses: true)
// 行ったら最初から(ループ)
.repeatForever(autoreverses: false)1.0 → 1.2 → 1.0 → 1.2 → … のように往復。パルスや呼吸のような動きに適している。
1.0 → 1.2 → 1.0 → 1.2 → … だが、1.2 から 1.0 への戻りは瞬時。回転やプログレスのような一方向の動きに適している。
repeatCount で回数指定
特定の回数だけ繰り返したい場合は repeatCount を使う。
.animation(
.easeInOut(duration: 0.5).repeatCount(3, autoreverses: true),
value: isShaking
)この例では 3 往復(6 回の動き)でアニメーションが停止する。注意を引くための短いアニメーションに便利だ。
回転アニメーション
無限回転は autoreverses: false との組み合わせが定番。
struct SpinningLoader: View {
@State private var isRotating = false
var body: some View {
Image(systemName: "arrow.triangle.2.circlepath")
.font(.system(size: 40))
.rotationEffect(.degrees(isRotating ? 360 : 0))
.animation(
.linear(duration: 1.0).repeatForever(autoreverses: false),
value: isRotating
)
.onAppear {
isRotating = true
}
}
}linear を使うことで、一定速度で回転し続ける。easeInOut だと回転が不自然に加減速してしまう。
シェイクアニメーション
入力エラーなどを知らせるシェイクアニメーションの例。
struct ShakingTextField: View {
@State private var text = ""
@State private var shake = false
var body: some View {
TextField("入力してください", text: $text)
.textFieldStyle(.roundedBorder)
.offset(x: shake ? -10 : 0)
.animation(
.easeInOut(duration: 0.1).repeatCount(5, autoreverses: true),
value: shake
)
}
func triggerShake() {
shake = true
// アニメーション終了後にリセット
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
shake = false
}
}
}短い duration と repeatCount で、素早い往復運動を実現する。
アニメーションの停止
repeatForever で開始したアニメーションを停止するには、状態を元に戻すか、animation(nil) を適用する。
struct ControllableAnimation: View {
@State private var isAnimating = false
@State private var scale: CGFloat = 1.0
var body: some View {
VStack {
Circle()
.fill(.green)
.frame(width: 100, height: 100)
.scaleEffect(scale)
.animation(
isAnimating
? .easeInOut(duration: 0.8).repeatForever(autoreverses: true)
: .default,
value: scale
)
Button(isAnimating ? "停止" : "開始") {
if isAnimating {
isAnimating = false
scale = 1.0
} else {
isAnimating = true
scale = 1.3
}
}
}
}
}アニメーションの種類自体を条件分岐で切り替えることで、開始・停止を制御できる。
パフォーマンスの注意点
repeatForever は CPU/GPU リソースを継続的に消費する。不要になったアニメーションは必ず停止し、画面外のビューでは onDisappear でアニメーションを止めるなどの配慮が必要だ。特に複数の要素を同時にアニメーションさせる場合は、バッテリー消費にも注意したい。