Limit rectangle to screen edge on drag gesture
Asked Answered
M

1

6

I'm just getting started with SwiftUI and I was hoping for the best way to tackle the issue of keeping this rectangle in the bounds of a screen during a drag gesture. Right now it goes off the edge until it reaches the middle of the square (I think cause I'm using CGPoint).

I tried doing some math to limit the rectangle and it succeeds on the left side only but it seems like an awful way to go about this and doesn't account for varying screen sizes. Can anyone help?

struct ContentView: View {
    @State private var pogPosition = CGPoint()
    
    var body: some View {
        PogSound()
            .position(pogPosition)
            .gesture(
                DragGesture()
                    .onChanged { value in
                        self.pogPosition = value.location
                        
                        // Poor solve
                        if(self.pogPosition.x < 36) {
                            self.pogPosition.x = 36
                        }
                }
                .onEnded { value in
                    print(value.location)
                }
        )
    }
}

enter image description here

Madera answered 1/9, 2020 at 18:0 Comment(0)
T
7

Here is a demo of possible approach (for any view, cause view frame is read dynamically).

Demo & tested with Xcode 12 / iOS 14

enter image description here

struct ViewSizeKey: PreferenceKey {
    static var defaultValue = CGSize.zero
    static func reduce(value: inout Value, nextValue: () -> Value) {
        value = nextValue()
    }
}

struct ContentView: View {
    @State private var pogPosition = CGPoint()
    @State private var size = CGSize.zero

    var body: some View {
        GeometryReader { gp in
            PogSound()
                .background(GeometryReader {
                    Color.clear
                        .preference(key: ViewSizeKey.self, value: $0.frame(in: .local).size)
                })
                .onPreferenceChange(ViewSizeKey.self) {
                    self.size = $0
                }
                .position(pogPosition)
                .gesture(
                    DragGesture()
                        .onChanged { value in
                            let rect = gp.frame(in: .local)
                                .inset(by: UIEdgeInsets(top: size.height / 2.0, left: size.width / 2.0, bottom: size.height / 2.0, right: size.width / 2.0))
                            if rect.contains(value.location) {
                                self.pogPosition = value.location
                            }
                        }
                        .onEnded { value in
                            print(value.location)
                        }
            )
            .onAppear {
                let rect = gp.frame(in: .local)
                self.pogPosition = CGPoint(x: rect.midX, y: rect.midY)
            }
        }.edgesIgnoringSafeArea(.all)
    }
}
Transfix answered 1/9, 2020 at 18:37 Comment(1)
Wow, there is so much for me to dive in and understand in this example. Really appreciate you taking the time to put this together. Totally blown away and exactly the result I was looking for.Madera

© 2022 - 2024 — McMap. All rights reserved.