Soltan Adel
Soltan Adel

Reputation: 15

Preventing SwiftUI rectangles from going outside active area during drag gesture

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()
        }
    }
}

Upvotes: 1

Views: 516

Answers (1)

yawnobleix
yawnobleix

Reputation: 1342

Does something like this match what you are looking for?

struct ContentView: View {
    @State var position = CGSize.zero
    @State private var rectangleSize = CGRect.zero
    var body: some View {
        GeometryReader { geometry in
            ZStack {
                Rectangle()
                    .fill(Color(red: 0.5450980392156862, green: 0.5450980392156862, blue: 0.5450980392156862))
                    .aspectRatio(0.75, contentMode: .fit)
                    .frame(width: 20, height: 50)
                    .overlay(
                        GeometryReader { geo in
                            Color.clear
                                .onAppear{
                                    rectangleSize = geo.frame(in: .global)
                                }
                        })
                    .cornerRadius(30)
                    .offset(position)
                    .animation(.spring(response: 0.4, dampingFraction: 0.4, blendDuration: 0.4))
                    .gesture(
                        DragGesture()
                            .onChanged({ value in
                                let xLoc = max(min(value.location.x, geometry.size.width - 1 * rectangleSize.width),0)
                                let yLoc = max(min(value.location.y, geometry.size.height - 1 * rectangleSize.height),0)
                                
                                position = CGSize(width: xLoc, height: yLoc)
                            })
                    )
            }
        }
    }
}

The main things that were changed are using the drag location instead of the translation and calculating the offset so that the width and heights have values greater than 0 but less than the screen width

Upvotes: 0

Related Questions