Library / Outcomes & notifications
Error with shake animation
Wrong password or invalid input: the field shakes while the error haptic buzzes — the lock-screen pattern.
import SwiftUI
struct PasscodeField: View {
@State private var code = ""
@State private var failedAttempts = 0
var body: some View {
SecureField("Passcode", text: $code)
.textFieldStyle(.roundedBorder)
.modifier(Shake(trigger: failedAttempts))
.sensoryFeedback(.error, trigger: failedAttempts)
.onSubmit {
if code != "1234" {
withAnimation(.default) { failedAttempts += 1 }
code = ""
}
}
}
}
/// Horizontal shake, synced to the same trigger as the haptic.
struct Shake: ViewModifier, Animatable {
var trigger: Int
var animatableData: CGFloat { get { CGFloat(trigger) } set { phase = newValue } }
private var phase: CGFloat = 0
init(trigger: Int) { self.trigger = trigger; self.phase = CGFloat(trigger) }
func body(content: Content) -> some View {
content.offset(x: sin(phase * .pi * 4) * 8)
}
} func showLoginError(on field: UITextField) {
UINotificationFeedbackGenerator().notificationOccurred(.error)
let shake = CAKeyframeAnimation(keyPath: "transform.translation.x")
shake.values = [0, -10, 10, -8, 8, -4, 4, 0]
shake.duration = 0.4
field.layer.add(shake, forKey: "shake")
}