> For the complete documentation index, see [llms.txt](https://lochiwei.gitbook.io/ios/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lochiwei.gitbook.io/ios/swiftui/anim/animatable/animatable-modifiers/.taptoshake.md).

# .tapToShake()

[SwiftUI](/ios/swiftui.md) ⟩ [Animations](/ios/swiftui/anim.md) ⟩ [Animatable](/ios/swiftui/anim/animatable.md) ⟩ [Modifiers](/ios/swiftui/anim/animatable/animatable-modifiers.md) ⟩&#x20;

![](/files/p8ml2FvUth8lPkyOmfk1)

{% tabs %}
{% tab title="💈範例" %}
{% hint style="success" %}

* 用 <mark style="color:purple;">**withAnimation()**</mark> 來設定 "<mark style="color:red;">**keyframe**</mark>" 的參數值。
* 用 [Animatable Modifiers](/ios/swiftui/anim/animatable/animatable-modifiers.md) 來計算內插於 <mark style="color:red;">**"keyframe" 之間**</mark>的 "frame"。
  {% endhint %}

{% hint style="info" %}
本例用兩種方式 (`TapToShake`, `TapToShake2`) 來設定 "<mark style="color:red;">**keyframe**</mark>" 的參數值。
{% endhint %}

```swift
import SwiftUI

struct ContentView: View {
    @State private var taps: CGFloat = 0
    var body: some View {
        VStack(spacing: 16) {
            Text("🍌 Shaking Banana 🍌")
                .foregroundColor(.yellow)
                .tapToShake()
            Text("👋 Shaking Hello 👋")
                .foregroundColor(.blue)
                .tapToShake2()
        }
        .font(.headline)
        .padding()
        .border(.secondary)
    }
}

// 👔 ShakeOffset
// calculate animation frame for shake effect at specific time `t`
struct ShakeOffset: Animatable, ViewModifier {
    
    var t: CGFloat = 0            // ⭐️ animation parameter
    let amplitude: CGFloat = 10
    
    // 🅿️ Animatable
    // ⭐️ animation parameter (for interpolation)
    var animatableData: CGFloat {
        get { t } 
        set { t = newValue }
    }
    
    // 🅿️ ViewModifier
    func body(content: Content) -> some View {
        content
            .offset(x: sin(t * .pi * 2) * amplitude)
    }
}

// 👔 TapToShake
struct TapToShake: ViewModifier {
    
    // ⭐️ "keyframe" parameter
    @State private var t: CGFloat = 0
    
    // 🅿️ ViewModifier
    func body(content: Content) -> some View {
        content
            // ⭐️ interpolates between "keyframes" using `ShakeOffset`
            .modifier(ShakeOffset(t: t))
            .onTapGesture {
                withAnimation(.linear(duration: 0.5)) {
                    // ⭐️ "keyframe" param 
                    //    t = 0, 3, 6, 9 ...
                    // 🔸 註解：
                    //    這種方式每次按都是先往右擺動。
                    t += 3
                }
            }
    }
}

// 👔 TapToShake2
struct TapToShake2: ViewModifier {
    
    @State private var flag = false
    
    // ⭐️ "keyframe" parameter
    var t: CGFloat { flag ? 1 : 0 }
    
    // 🅿️ ViewModifier
    func body(content: Content) -> some View {
        content
            // ⭐️ interpolates between "keyframes" using `ShakeOffset`
            .modifier(ShakeOffset(t: t))
            .onTapGesture {
                withAnimation(.linear(duration: 0.5).repeatCount(3, autoreverses: false)) {
                    // ⭐️ "keyframe" param toggles between 0 and 1
                    //    t = 0, 1, 0, 1 ...
                    // 🔸 註解：
                    //    這種方式第一次按會先往右擺動，第二次按會先往左擺動。
                    flag.toggle()
                }
            }
    }
}

// 🌀 View+
extension View {
    /// `view.tapToShake()`
    func tapToShake() -> some View {
        modifier(TapToShake())
    }
    
    /// `view.tapToShake2()`
    func tapToShake2() -> some View {
        modifier(TapToShake2())
    }
}
```

{% endtab %}

{% tab title="📗 參考" %}

* SwiftOnTap ⟩ [Animatable](https://swiftontap.com/animatable) ⭐️
  {% endtab %}
  {% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://lochiwei.gitbook.io/ios/swiftui/anim/animatable/animatable-modifiers/.taptoshake.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
