skip to Main Content

I am trying to create app that allows user to drag through the grid, and change colour of each touched cell. Some kind of pixel art drawing machine, but after making simple example it doesn’t work, and I don’t know why.

Here is my code:

struct Cell: View, Hashable, Equatable {
    @State var color: Color = .red
    let id = UUID()
    
    static func == (lhs: Cell, rhs: Cell) -> Bool {
        return lhs.color == rhs.color
    }

    func hash(into hasher: inout Hasher) {
        hasher.combine(color)
    }

    var body: some View {
        Rectangle()
            .frame(width: 40, height: 40)
            .foregroundColor(color)
    }
}

struct Grid: View {
    
    @State private var cells: [[Cell]] = (0..<10).map { _ in
        (0..<10).map { _ in Cell() }
    }

    var body: some View {
        VStack(spacing: 0) {
            ForEach(cells, id: .self) { row in
                HStack(spacing: 0) {
                    ForEach(row, id: .id) { cell in
                        cell
                    }
                }
            }
        }
        .background(Color.black)
        .gesture(
            DragGesture()
                .onChanged { value in
                    let width = 40
                    let height = 40
                    let x = Int(value.location.x / CGFloat(width))
                    let y = Int(value.location.y / CGFloat(height))
                    // Make sure the indices are within the bounds of the grid
                    if x >= 0 && x < 10 && y >= 0 && y < 10 {
                        self.cells[y][x].color = .green
                    }
                }
        )
    }
}

2

Answers


  1. It’s good to create separate models for cells.
    here is a quick fix.

    struct CellView: View {
        var cell: Cell
        
        var body: some View {
            Rectangle()
                .frame(width: 40, height: 40)
                .foregroundColor(cell.color)
        }
    }
    
    struct Cell: Identifiable {
        var color: Color = .red
        let id = UUID()
    }
    
    struct Grid: View {
        
        @State private var cells: [[Cell]] = (0..<10).map { _ in
            (0..<10).map { _ in Cell() }
        }
        
        var body: some View {
            VStack(spacing: 0) {
                ForEach(cells.indices, id: .self) { row in
                    HStack(spacing: 0) {
                        ForEach(cells[row], id: .id) { cell in
                            CellView(cell: cell)
                        }
                    }
                }
            }
            .background(Color.black)
            .gesture(
                DragGesture()
                    .onChanged { value in
                        let width = 40
                        let height = 40
                        let x = Int(value.location.x / CGFloat(width))
                        let y = Int(value.location.y / CGFloat(height))
                        // Make sure the indices are within the bounds of the grid
                        if x >= 0 && x < 10 && y >= 0 && y < 10 {
                            self.cells[y][x].color = .green
                        }
                    }
            )
        }
    }
    

    enter image description here

    Login or Signup to reply.
  2. @raja-kishan approach is good but you can just remove @State from @State var color: Color = .red from your Cell Struct like this.

    struct Cell: View, Hashable, Equatable {
        var color: Color = .red
        let id = UUID()
        
        static func == (lhs: Cell, rhs: Cell) -> Bool {
            return lhs.color == rhs.color
        }
    
        func hash(into hasher: inout Hasher) {
            hasher.combine(color)
        }
    
        var body: some View {
            Rectangle()
                .frame(width: 40, height: 40)
                .foregroundColor(color)
        }
    }
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search