I am building a simple drag gesture animation in a Rectangle() that, in the end of the gesture, stick the shape in the closest item of a group.
Check the example in the image bellow.
I was able to achieve a decent result with the following approach:
Manually computing the x absolute position of the black rectangles:
@State private var xPos : [Int] = [40,110,180,250,320]
Placing the rectangles in the screen with a absolute position property:
Rectangle() .position(x: CGFloat(xPos[i]), y: 0)Finally, in the blue Rectangle, add the gesture property, with a fancy func on .onEnded to find the closest element, and apply the x position accordingly.
Rectangle() .fill(.blue) .position(location) .gesture( DragGesture() .onChanged { gesture in location.x = gesture.location.x } .onEnded { value in withAnimation(.spring()) { var goal = Int(value.location.x) var closest = xPos[0] var index = 0 for item in xPos { var distanceToActual = abs(closest - goal) if (xPos.count - 1 > index) { // prevent out of the bound var distanceToNext = abs(xPos[index + 1] - goal) if(distanceToNext < distanceToActual) { closest = xPos[index + 1] } } index += 1 } location.x = CGFloat(closest) } }
My question is, is there a more elegant way of doing it? It's very annoying to manually calc the position of the Black rectangles... Is there any way of doing this with the Black Rectangles placed in a HStack instead of manually position then?

The technique described in the answer to Is it possible to detect which View currently falls under the location of a DragGesture? can be used to detect, which of the squares is closest to the drag position (it was my answer).
matchedGeometryEffectthen provides a convenient way to match the position of the blue rectangle to the identified square.Like this: