What you’re describing is about as basic as life gets. Simply think about the notion of a grid and the xy coordinates of one piece within the grid. Now you know where to place each subview.
Here, to show you the general idea, is a simplified version of what you’re doing. Imagine that we have no blank areas: just a solid grid of squares that are either red or gray. And let’s imagine that this grid is 12×8.
So to start with, how would we just construct a 12×8 grid of gray squares? In your code, you are doing it with actual drawing, in draw(_:)
; my approach uses subviews (and sublayers is also a possibility, if you think subviews is too much overhead), but the underlying principle is exactly the same:
// assume 12x8 squares
let xmax = 12, ymax = 8
let w = self.view.bounds.width / CGFloat(xmax)
for i in 0..<xmax {
for j in 0..<ymax {
let rect = CGRect(x: w*CGFloat(i), y: w*CGFloat(j), width: w, height: w).insetBy(dx: 2, dy: 2)
let v = UIView(frame:rect)
// v.backgroundColor = withRedOnes.contains([i,j]) ? .red : .gray
v.backgroundColor = .gray
self.view.addSubview(v)
}
}
Do you see the key concept? i
and j
are the grid placement of a square. From that, we can easily calculate the rect
where that square goes. That’s all there is to it!
Now specifying that something different, like a red view, goes at any particular coordinate, is trivial:
func makeGrid(withRedOnes: [[Int]]) {
// assume 12x8 squares
let xmax = 12, ymax = 8
let w = self.view.bounds.width / CGFloat(xmax)
for i in 0..<xmax {
for j in 0..<ymax {
let rect = CGRect(x: w*CGFloat(i), y: w*CGFloat(j), width: w, height: w).insetBy(dx: 2, dy: 2)
let v = UIView(frame:rect)
v.backgroundColor = withRedOnes.contains([i,j]) ? .red : .gray
self.view.addSubview(v)
}
}
}
If we call that method like this:
self.makeGrid(withRedOnes:[[6,3], [7,3]])
Then we get this:
Okay, now. In real life, you’re not doing to use a mere UIView as each square. You will have your own UIView subclass that knows how to draw itself: with a color, with a number, whataever. And you won’t reconstruct all the views every time something changes; you will just change that one view within the grid, removing it or placing it, changing the way it draws itself, whatever.
As practice, I suggest you try writing a simpler grid-based app, such as a tic-tac-toe game (3×3 grid of “O” and “X”). Once you have that down, you will just tweak it successively to do all sorts of fancy things, like offsetting or centering a row of the grid and other requirements you may have in order to “draw” a theatre layout.
CLICK HERE to find out more related problems solutions.