if the user stops touching the view before seconds have elapsed or moves their finger more than points SwiftUI does not invoke the callback.
⭐️ .onChanged()
只要摸到,就會觸發,但「只觸發一次」,就算摸再久,也只觸發一次,不會連續觸發,附送的 value 總是 true。但「每摸一次,就觸發一次」。
📗 參考:, Ch. 17: Using Gestures (p.371)
import SwiftUI
struct ContentView: View {
// star image size state (true: small, false: big)
@State private var isSmallStar = false
// ⭐️ `@GestureState` tracks the state change of a gesture
// `isStarPressed` indicates whether a tap event is detected
@GestureState private var isStarPressed = false
var body: some View {
Image(systemName: "star.circle.fill")
.font(.system(size: 200))
// ⭐️ dimmer when star is pressed
.opacity(isStarPressed ? 0.4 : 1)
.scaleEffect(isSmallStar ? 0.5 : 1.0)
.animation(.easeInOut)
.foregroundColor(.yellow)
.overlay(
Text(verbatim: "\(isStarPressed)")
.foregroundColor(isStarPressed ? .pink : .secondary)
)
.gesture(
LongPressGesture(minimumDuration: 1.0)
// on pressed: (tap and hold)
// ⭐️ update `@GestureState` var as the gesture's value changes.
// • value: LongPressGesture.Value == Bool (current value)
// gesture's current value (`true` indicates a tap is detected)
// • state: inout State == Bool (previous gesture's value)
// `state` == `isStarPressed` in this case
// • transaction:
// stores the "context"(?) of the gesture.
.updating($isStarPressed) { (value, state, _) in
// ⭐️ save current value (is pressed or not?)
state = value
}
// on long pressed:
// • value: LongPressGesture.Value == Bool (gesture's final value)
// 🔸 註:
// 只有時間超過 `minimumDuration` 才會引發 onEnded❗️
// 而且 `isStarPressed` 會馬上變為 false❗️
.onEnded { _ in
// ⭐️ toggle image size when long pressed
isSmallStar.toggle()
}
)
}
}