1

I'm trying to use a LazyVGrid in SwiftUI where you can touch and drag your finger to select multiple adjacent cells in a specific order. This is not drag and drop, and I don't want to move the cells (maybe drag isn't the right term here, but couldn't think of another one to describe it). Also, you would be able to reverse the selection (ie: each cell can only be selected once and reversing direction would un-select the cell). How can I accomplish this? Thanks!

For example:

struct ContentView: View {

    @EnvironmentObject private var cellsArray: CellsArray
        
    var body: some View {
        VStack {
            LazyVGrid(columns: gridItems, spacing: spacing) {
                ForEach(0..<(rows * columns), id: \.self){index in
                    VStack(spacing: 0) {
                        CellsView(index: index)
                    }
                }
            }
        }
    }
}
struct CellsView: View {
            
    @State var index: Int
    @EnvironmentObject var cellsArray: CellsArray

    var body: some View {
       ZStack {
           Text("\(self.cellsArray[index].cellValue)") //cellValue is a string
               .foregroundColor(Color.yellow)
               .frame(width: getWidth(), height: getWidth())
               .background(Color.gray)
       }
       //.onTapGesture ???
    }
    func getWidth()->CGFloat{
                
        let width = UIScreen.main.bounds.width - 10
        
        return width / CGFloat(columns)
        
    }
}
Timmy
  • 4,098
  • 2
  • 14
  • 34
CS0521
  • 152
  • 2
  • 9

1 Answers1

-1

Something like this might help, the only issue here is the coordinate space. Overlay is not drawing the rectangle in the correct coordinate space.

struct ImagesView: View {
    var columnSize: CGFloat
    @Binding var projectImages: [ProjectImage]
    @State var selectedImages: [ImageSelection] = []
    @State var dragWidth: CGFloat = 1.0
    @State var dragHeight: CGFloat = 1.0
    @State var dragStart: CGPoint = CGPoint(x:0, y:0)
    let columns = [
        GridItem(.adaptive(minimum: 200), spacing: 0)
    ]
    
    var body: some View {
        GeometryReader() { geometry in
            ZStack{
                ScrollView{
                    LazyVGrid(columns: [
                        GridItem(.adaptive(minimum: columnSize), spacing: 2)
                    ], spacing: 2){
                        ForEach(projectImages, id: \.imageUUID){ image in
                            Image(nsImage: NSImage(data: image.imageData)!)
                                .resizable()
                                .scaledToFit()
                                .border(selectedImages.contains(where: {imageSelection in imageSelection.uuid == image.imageUUID}) ? Color.blue : .primary, width: selectedImages.contains(where: {imageSelection in imageSelection.uuid == image.imageUUID}) ? 5.0 : 1.0)
                                
                                .gesture(TapGesture(count: 2).onEnded{
                                    print("Double tap finished")
                                })
                                .gesture(TapGesture(count: 1).onEnded{
                                    if selectedImages.contains(where: {imageSelection in imageSelection.uuid == image.imageUUID}) {
                                        print("Image is already selected")
                                        if let index = selectedImages.firstIndex(where: {imageSelection in imageSelection.uuid == image.imageUUID}){
                                            selectedImages.remove(at: index)
                                        }
                                        
                                    } else {
                                        selectedImages.append(ImageSelection(imageUUID: image.imageUUID))
                                        print("Image has been selected")
                                    }
                                })
                        }
                    }
                    .frame(minHeight: 50)
                    .padding(.horizontal, 1)
                }
                .simultaneousGesture(
                    DragGesture(minimumDistance: 2)
                        .onChanged({ value in
                            print("Drag Start: \(value.startLocation.x)")
                            self.dragStart = value.startLocation
                            self.dragWidth = value.translation.width
                            self.dragHeight = value.translation.height
                        })
                )
                .overlay{
                    Rectangle()
                        .frame(width: dragWidth, height: dragHeight)
                        .offset(x:dragStart.x, y:dragStart.y)
                }
                
            }
        }
    }
}