Last updated
Was this helpful?
Last updated
Was this helpful?
⟩ ⟩ ⟩ ⟩
用 withAnimation() 來設定 "keyframe" 的參數值。
用 來計算內插於 "keyframe" 之間的 "frame"。
本例用兩種方式 (TapToShake
, TapToShake2
) 來設定 "keyframe" 的參數值。
SwiftOnTap ⟩ ⭐️
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())
}
}