I'm working on a SwiftUI project where I have one rectangle that I want to be draggable within an active area. However, I'm facing an issue where the rectangle can go outside the active area during the drag gesture. I want to constrain the position of the rectangle so that it stays within the active area during the drag gesture. How can I achieve this? Any insights or suggestions would be greatly appreciated. Thank you in advance!
Here's a simplified version of my code:
struct ContentView: View {
@State var position = CGSize.zero
@State var lastPosition = CGSize.zero
var body: some View {
ZStack {
Rectangle()
.fill(Color(red: 0.5450980392156862, green: 0.5450980392156862, blue: 0.5450980392156862))
.aspectRatio(0.75, contentMode: .fit)
.frame(height: 550)
.cornerRadius(30)
.offset(x: position.width, y: position.height)
.animation(.spring(response: 0.4, dampingFraction: 0.4, blendDuration: 0.4))
.gesture(
DragGesture()
.onChanged({ value in
position = CGSize(width: lastPosition.width + value.translation.width, height: lastPosition.height + value.translation.height)
})
.onEnded({ value in
lastPosition = position
})
)
.padding()
}
}
}
A simple way is to compute those limits yourself and forbid to overpass.
Here is some sample code you could adapt:
@State private var location: CGPoint = CGPoint(x: 700, y: 500) // Set a default value
@GestureState private var startLocation: CGPoint? = nil
var parentViewSize: CGSize = CGSize(width: 600, height: 400) // The size of your parentView
.gesture(
DragGesture()
.onChanged { value in
var newLocation = startLocation ?? location
newLocation.x += value.translation.width
newLocation.y += value.translation.height
if newLocation.x < 200 { newLocation.x = 200 } // 200 to be replaced by a value depending on Rectangle width
if newLocation.x > parentViewSize.width - 100 { newLocation.x = parentViewSize.width - 100 } // 100 to be replaced by a value depending on Rectangle height
if newLocation.y < 200 { newLocation.y = 200 } // 200 to be replaced by a value depending on Rectangle height
if newLocation.y > parentViewSize.height - 100 { newLocation.y = parentViewSize.height - 100 } // 200 to be replaced by a value depending on Rectangle height
self.location = newLocation
}
.updating($startLocation) { (value, startLocation, transaction) in
startLocation = startLocation ?? location
}
)
You can also use geometryReader as described here: https://stackoverflow.com/questions/62512494/how-to-restrict-drag-gesture-to-particular-frame-only-in-swiftui