Skip to content

Instantly share code, notes, and snippets.

@schwa
Last active October 15, 2022 00:18
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save schwa/63c80eece04329423ec40dc87d33071e to your computer and use it in GitHub Desktop.
Save schwa/63c80eece04329423ec40dc87d33071e to your computer and use it in GitHub Desktop.
Flick Gesture
import PlaygroundSupport
import SwiftUI
PlaygroundPage.current.setLiveView(ContentView())
struct ContentView: View {
var body: some View {
Color.white.frame(width: 600, height: 800).touchVisualizer()
}
}
struct TouchVisualizerModifier: ViewModifier {
@State
var state: DragGesture.Value?
@State
var realToPredicted: Double = 0
func body(content: Content) -> some View {
content
.overlay {
WatchedAnimation(value: realToPredicted) { realToPredicted in
Canvas { context, size in
guard let state else {
return
}
context.stroke(Path(ellipseIn: .init(center: state.startLocation, radius: 8)), with: .color(.red))
context.fill(Path(ellipseIn: .init(center: state.predictedEndLocation, radius: 8)), with: .color(.red.opacity(0.5)))
let simulated = lerp(from: state.location, to: state.predictedEndLocation, by: realToPredicted)
context.fill(Path(ellipseIn: .init(center: simulated, radius: 8)), with: .color(.red))
}
}
}
.gesture(
DragGesture(minimumDistance: 0)
.onChanged { value in
realToPredicted = 0
state = value
}
.onEnded { value in
state = value
withAnimation(.linear(duration: 0.3)) {
realToPredicted = 1.0
}
}
)
}
}
extension View {
func touchVisualizer() -> some View {
modifier(TouchVisualizerModifier())
}
}
struct WatchedAnimation <Content, Value>: View, Animatable where Content: View, Value: VectorArithmetic {
var value: Value
var animatableData: Value {
get {
return value
}
set {
value = newValue
}
}
let content: (Value) -> Content
var body: some View {
content(value)
}
}
public func lerp(from v0: CGPoint, to v1: CGPoint, by t: Double) -> CGPoint {
CGPoint(x: (1 - t) * v0.x + t * v1.x, y: (1 - t) * v0.y + t * v1.y)
}
extension CGRect {
init(center: CGPoint, radius: CGFloat) {
self = CGRect(x: center.x - radius, y: center.y - radius, width: radius * 2, height: radius * 2)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment