wlucas30
wlucas30

Reputation: 31

How can I activate multiple buttons in one slide gesture with SwiftUI?

I have 25 buttons laid out in a grid for a game like this.

I'm generating these buttons like this:

VStack {
  ForEach(1..<6) {_ in
    HStack {
      ForEach(1..<6) {_ in
        Button(action: {
          // Button clicked
          doButton()
        }) {
          Rectangle()
            .frame(width: 50, height: 50)
            .border(Color.black, lineWidth: 1)
        }
      }
    }
  }
}

How can I make it so if the user drags their finger across multiple buttons, each one of the buttons are clicked, and doButton() is executed?

I tried using a DragGesture() but couldn't get it to work...

Upvotes: 3

Views: 910

Answers (2)

Mike Lee
Mike Lee

Reputation: 2639

import SwiftUI

class Container : ObservableObject {
    @Published var location = CGPoint()
    public func updateLocation(_ location: CGPoint) {
        self.location = location
    }
}

struct SliderGestureButtonsView: View {
    @ObservedObject var container = Container()
    var body: some View {
        VStack(alignment: .center, spacing: 0) {
            ForEach(1..<6) { colY in
                HStack {
                    ForEach(1..<6) { rowX in
                        GeometryReader { gp in
                            let x = gp.frame(in:.named("hive")).midX
                            let y = gp.frame(in:.named("hive")).midY
                            let w = gp.frame(in:.named("hive")).size.width
                            let h = gp.frame(in:.named("hive")).size.height
                            let rect = CGRect(x: x, y: y, width: w, height: h)
                            boxView(row: rowX, col: colY, rect: rect, container: container)
                        }
                    }
                }.frame(height: 60)
            }
        }.coordinateSpace(name: "hive").frame(width: 300)
        .gesture(
            DragGesture(minimumDistance: 0, coordinateSpace: CoordinateSpace.named("hive"))
            .onChanged { (value) in
                container.updateLocation(value.location)
            }
        )
    }
}


struct boxView: View {
    var row: Int
    var col: Int
    var rect: CGRect
    @ObservedObject var container: Container
    var body: some View {
        let x = container.location.x
        let y = container.location.y
        
        let hw = rect.size.width / 2
        let ox = rect.origin.x
        let withinX = x > ox - hw && x < ox + hw
        
        let hh = rect.size.height / 2
        let oy = rect.origin.y
        let withinY = y > oy - hh && y < oy + hh
        
        var pressed = false

        if(withinX && withinY) {
            pressed = true
            print("trigger ", self.row, self.col)
        }

        return Rectangle()
                .stroke(Color.white)
                .frame(width: 60, height: 60)
                .background(pressed ? Color.green : Color.black)
    }
}

Upvotes: 1

user3069232
user3069232

Reputation: 8995

Swift 5.1, iOS 13.

I don't have a 100% solution for you, but I do have something to get you off the ground hopefully. These are not buttons, but simply squares. As I click/drag across them they^ll signal I passed by.

It isn't perfect, but should give you some thing more to work with. I read a tutorial on medium on doing something similar with drag and drop. This one.

Can help but think you'll need to do something with drag here and the Geometry reader ultimately, detecting where they are and responding to that.

import SwiftUI

struct ContentView: View {
var body: some View {
 return VStack {
  ForEach(1..<6) {colY in
    HStack {
      ForEach(1..<6) {rowX in
          boxView(row: rowX, col: colY)
        }
      }
    }
  }
}
}

struct boxView: View {
 @State var row: Int
 @State var col: Int
 var body: some View {
 let dragGesture = DragGesture(minimumDistance: 0, coordinateSpace: CoordinateSpace.global)
  .onChanged { (value) in
    print("trigger ",self.row,self.col)
  }
 return Rectangle()
    .stroke(Color.black)
    .frame(width: 50, height: 50)
    .gesture(dragGesture)
  }
}

Upvotes: 1

Related Questions