2

Below is the code I wrote for dragging a rectangle. I would like to restrict its dragging to be within the border of the view given. ie if the user tries to move the rectangle outside the border of the view, it should stay within the border edges. I tried using GeometryReader to get the rect of both the rectangle and the outer view, but I am unable to restrict the drag. Please help.

import SwiftUI

struct DragView: View {
    @State private var currentPosition: CGSize = .zero
    @State private var newPosition: CGSize = .zero
    @State private var parentRect: CGRect = .zero
    @State private var childRect: CGRect = .zero

    var body: some View {
            VStack {
                Rectangle().frame(width: 100, height: 100, alignment: .top)
                    .foregroundColor(.blue)
                    .offset(x: self.currentPosition.width, y: self.currentPosition.height)
                    .background(GeometryGetter(rect: $childRect))

                .gesture(
                    DragGesture(minimumDistance: 0, coordinateSpace: .global)
                        .onChanged { value in
                            self.currentPosition = CGSize(width: value.translation.width + self.newPosition.width, height: value.translation.height + self.newPosition.height)
                        }
                        .onEnded { value in
                            self.currentPosition = CGSize(width: value.translation.width + self.newPosition.width, height: value.translation.height + self.newPosition.height)
                            self.newPosition = self.currentPosition
                        }
                )
            }
            .frame(width: 300, height: 500, alignment: .center)
            .border(Color.black, width: 1)
            .background(GeometryGetter(rect: $parentRect))
    }
}

struct GeometryGetter: View {
    @Binding var rect: CGRect

    var body: some View {
        GeometryReader { geometry in
            Group { () -> AnyView in
                DispatchQueue.main.async {
                    self.rect = geometry.frame(in: .global)
                }
                return AnyView(Color.clear)
            }
        }
    }
}

1 Answer 1

2

check this out:

struct ContentView: View {
    @State private var currentPosition: CGSize = .zero
    @State private var newPosition: CGSize = .zero
    @State private var parentRect: CGRect = .zero
    @State private var childRect: CGRect = .zero

    func correctPostion() {
        print(self.currentPosition)
        if self.currentPosition.width > 100 {
            self.currentPosition.width = 100
        }
        if self.currentPosition.height > 200 {
            self.currentPosition.height = 200
        }
        if self.currentPosition.width < -100 {
            self.currentPosition.width = -100
        }
        if self.currentPosition.height < -200 {
            self.currentPosition.height = -200
        }
    }

    var body: some View {
            VStack {
                Rectangle().frame(width: 100, height: 100, alignment: .top)
                    .foregroundColor(.blue)
                    .offset(x: self.currentPosition.width, y: self.currentPosition.height)
                    .background(GeometryGetter(rect: $childRect))

                .gesture(
                    DragGesture(minimumDistance: 0, coordinateSpace: .global)
                        .onChanged { value in
                            self.currentPosition = CGSize(width: value.translation.width + self.newPosition.width, height: value.translation.height + self.newPosition.height)

                            self.correctPostion()
                        }
                        .onEnded { value in
                            self.currentPosition = CGSize(width: value.translation.width + self.newPosition.width, height: value.translation.height + self.newPosition.height)

                            self.correctPostion()

                            self.newPosition = self.currentPosition
                        }
                )
            }
            .frame(width: 300, height: 500, alignment: .center)
            .border(Color.black, width: 1)
            .background(GeometryGetter(rect: $parentRect))
    }
}

struct GeometryGetter: View {
    @Binding var rect: CGRect

    var body: some View {
        GeometryReader { geometry in
            Group { () -> AnyView in
                DispatchQueue.main.async {
                    self.rect = geometry.frame(in: .global)
                }
                return AnyView(Color.clear)
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.