はじめに
パスワードの入力欄でよくあるのが、間違ったパスワードを入力すると入力欄がシェイク(ブルブル)して間違っていることを知らせるといったUIです。
これをiOS17から登場したkeyframeAnimatorを使って実装してみたいと思います。
keyframeAnimatorを使用せず、実装したい場合は以下の記事が参考になると思います。
サンプルアプリ
キーボードでreturnを押すと、テキストフィールドがシェイクします。
間違ったものを入力していたという想定です。

実装
import SwiftUI
struct KeyframeAnimationValues {
var offsetX = 0.0
}
struct ContentView: View {
@State private var text = ""
@State private var shakeAnimationTrigger = false
var body: some View {
VStack {
TextField("文字を入力してください", text: $text)
.textFieldStyle(.roundedBorder)
.keyframeAnimator(
initialValue: KeyframeAnimationValues(),
trigger: shakeAnimationTrigger
) { content, value in
content.offset(x: value.offsetX)
} keyframes: { _ in
KeyframeTrack(\.offsetX) {
CubicKeyframe(5, duration: 0.2)
CubicKeyframe(-5, duration: 0.1)
CubicKeyframe(5, duration: 0.1)
CubicKeyframe(-5, duration: 0.1)
CubicKeyframe(5, duration: 0.1)
CubicKeyframe(0, duration: 0.2)
}
}
.onSubmit {
shakeAnimationTrigger.toggle()
}
}
.padding(20)
}
}
解説
アニメーションで必要な値を構造体で定義します。
今回はoffsetのxをいじりたいのでoffsetXを定義します。
struct KeyframeAnimationValues {
var offsetX = 0.0
}
アニメーションのトリガーを定義します。
@State private var shakeAnimationTrigger = false
initialValueには先ほど作成した構造体を初期化して渡します。
triggerに先ほど定義したトリガーを渡します。
keyframesで継続時間と値をセットで渡します。
keyframesで設定した値がvalueとして流れてくるので、content.offset(x:)でvalue.offsetXを設定します。
.keyframeAnimator(
initialValue: KeyframeAnimationValues(),
trigger: shakeAnimationTrigger
) { content, value in
content.offset(x: value.offsetX)
} keyframes: { _ in
KeyframeTrack(\.offsetX) {
CubicKeyframe(5, duration: 0.2)
CubicKeyframe(-5, duration: 0.1)
CubicKeyframe(5, duration: 0.1)
CubicKeyframe(-5, duration: 0.1)
CubicKeyframe(5, duration: 0.1)
CubicKeyframe(0, duration: 0.2)
}
}
今回はonSubmitで毎回シェイクされるようにshakeAnimationTriggerをtoggle()します。
shakeAnimationTrigger = trueのようにすると値がfalseに戻らないので正常に動作しません。
.onSubmit {
shakeAnimationTrigger.toggle()
}
おわり
KeyframeAnimationについて以前書いた記事はこちらです。
KeyframeAnimationがあると色んなアニメーションが作れて楽しいです