Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
415 views
in Technique[技术] by (71.8m points)

ios - SwiftUI: Drag and Drop, Prevent overlapping child Views

I am creating an application where the user can configure custom spots (circles) for spot booking in events via drag and drop.

Each spot is a Circle filled with a gesture that detects dragging and updates the position if it does not overlap with an existing spot by passing the callbacks from the parent view (ContentView) to the child view (Spot). This works, however, I am only able to drag the spots one by one position before it stops, although my cursor is still dragging.

Current behaviour: https://imgur.com/a/hlXOcuZ

Expected behaviour: https://imgur.com/a/1UI57wj

This is my simplified ContentView.swift

struct ContentView: View {
    @State var spots: [CGPoint] = [CGPoint(x: 100, y: 100), CGPoint(x: 200, y: 200)]
    var body: some View {
        ZStack {
            ForEach(spots, id: .x) {point in
                Spot(location: point,
                     checkOverlap: {point in
                    let overlappingSpots = spots.filter{spot in
                        let distance = calculateDistance(centerOne: point, centerTwo: spot)
                        return overlaps(distance: distance, radius: 25)
                    }
                    return overlappingSpots.count > 0
                },
                     updatePosition: {newPosition, oldPosition in
                        self.spots = spots.map{spot in
                            if (spot != oldPosition) {
                                return spot
                            }
                            return newPosition
                        }
                     })
            }
        }
    }
    
    private func calculateDistance(centerOne: CGPoint, centerTwo: CGPoint) -> CGFloat {
        let xSquared = pow(centerOne.x - centerTwo.x, 2)
        let ySquared = pow(centerOne.y - centerTwo.y, 2)
        return sqrt(xSquared + ySquared)
    }
    
    private func overlaps(distance: CGFloat, radius: CGFloat) -> Bool {
        return distance > 0 && distance < (radius + radius)
    }
    
}

and my Spot.swift

struct Spot: View {
    @GestureState private var startLocation: CGPoint?
    @State var currentLocation: CGPoint
    var checkOverlap: (CGPoint) -> Bool
    var updatePosition: (CGPoint, CGPoint) -> Void
    
    init(location: CGPoint, 
         checkOverlap: @escaping (CGPoint) -> Bool, 
         updatePosition: @escaping (CGPoint, CGPoint) -> Void) {
        self.checkOverlap = checkOverlap
        self.updatePosition = updatePosition
        _currentLocation = State(initialValue: location)
    }

    var body: some View {
        let dragGesture = DragGesture()
              .onChanged { value in
                  var newLocation = startLocation ?? currentLocation
                  newLocation.x += value.translation.width
                  newLocation.y += value.translation.height
                  let overlaps = checkOverlap(newLocation)
                  if (overlaps) {
                    return
                  }
                let existingLocation = self.currentLocation
                self.currentLocation = newLocation
                updatePosition(newLocation, existingLocation)
              }.updating($startLocation) { value, state, transaction in
                  state = state ?? currentLocation
              }
        return Circle()
        .fill(Color.red)
        .frame(width: 50, height: 50)
        .position(currentLocation)
        .gesture(dragGesture)
    }
}

question from:https://stackoverflow.com/questions/65874227/swiftui-drag-and-drop-prevent-overlapping-child-views

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...