soleil
soleil

Reputation: 13135

Checking for view overlapping in SwiftUI

See the comment in the code below.

struct ContentView: View {
    @State private var offset = CGSize.zero

    var body: some View {
        VStack {
            Circle()
                .fill(.blue)
                .frame(width: 200, height: 200)
            
            Circle()
                .fill(.red)
                .frame(width: 100, height: 100)
                .offset(offset)
                .gesture(
                    DragGesture()
                        .onChanged { gesture in
                            offset = gesture.translation
                        }
                        .onEnded { _ in
                            //how to check if the small red circle is more than halfway into the large blue circle???
                        }
                )
        }
        
        
    }
}

Or more generally, how can you check for view intersection/overlapping in SwiftUI?

Upvotes: 0

Views: 78

Answers (1)

Benzy Neez
Benzy Neez

Reputation: 22253

You can use a GeometryReader in the background of each shape to find their frames in the global coordinate space.

To determine if the red circle is more than half inside the blue circle, you can test whether the mid-point of the red frame is enclosed within the path of the blue circle.

To have the offset reset automatically, I changed the state variable to a GestureState.

struct ContentView: View {
    @GestureState private var offset = CGSize.zero
    @State private var bluePath: Path?
    @State private var isMoreThanHalfInside = false

    var body: some View {
        VStack {
            Circle()
                .fill(.blue)
                .frame(width: 200, height: 200)
                .background(
                    GeometryReader { proxy in
                        let frame = proxy.frame(in: .global)
                        Color.clear
                            .onAppear {
                                bluePath = Circle().path(in: frame)
                            }
                    }
                )

            Circle()
                .fill(isMoreThanHalfInside ? .yellow : .red)
                .opacity(offset == .zero ? 1 : 0.9)
                .overlay(Image(systemName: "plus").fontWeight(.thin))
                .frame(width: 100, height: 100)
                .background(
                    GeometryReader { proxy in
                        let frame = proxy.frame(in: .global)
                        let midPoint = CGPoint(x: frame.midX, y: frame.midY)
                        Color.clear
                            .onChange(of: midPoint) { oldVal, newVal in
                                isMoreThanHalfInside = bluePath?.contains(newVal) ?? false
                            }
                    }
                )
                .offset(offset)
                .gesture(
                    DragGesture(minimumDistance: 0)
                        .updating($offset) { val, state, trans in
                            state = val.translation
                        }
                )
        }
    }
}

Animation

Upvotes: 1

Related Questions