Skip to content

Instantly share code, notes, and snippets.

@DevonMartin
Created August 22, 2023 23:40
Show Gist options
  • Save DevonMartin/e235ccd6d146c179ebab568253648020 to your computer and use it in GitHub Desktop.
Save DevonMartin/e235ccd6d146c179ebab568253648020 to your computer and use it in GitHub Desktop.
Drag me!
struct ContentView: View {
var body: some View {
NodeRenderer(views: [
Node {
Text("Drag me!")
}
])
}
}
@Observable
class NodeState {
var pos: CGPoint
init(pos: CGPoint) {
self.pos = pos
}
}
protocol NodeObject: View {
var state: NodeState { get set }
}
struct Node<Content: View>: NodeObject {
@State var state = NodeState(pos: CGPoint(x: 100, y: 100))
@State var previousDrag: CGSize = .zero
@State var content: () -> Content
var drag: some Gesture {
DragGesture(coordinateSpace: .global)
.onChanged(updatePOS)
.onEnded(resetPOS)
}
var body: some View {
content()
.gesture(drag)
}
func updatePOS(value: DragGesture.Value) {
state.pos = CGPoint(
x: state.pos.x + value.translation.width - self.previousDrag.width,
y: state.pos.y + value.translation.height - self.previousDrag.height
)
self.previousDrag = value.translation
}
func resetPOS(_ ignored: DragGesture.Value) {
self.previousDrag = .zero
}
}
struct NodeRenderer: View {
@State var views: [any NodeObject]
var body: some View {
ForEach(Array(zip(views.indices, views)), id: \.0) { _, nodeObject in
AnyView(nodeObject)
.position(nodeObject.state.pos)
}
}
}
#Preview("Nodes") {
ContentView()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment