|
So another "why is this hard" question:
I have a fairly simple grid layout:
struct ContentView: View {
@State var gridSize = 3
@State var selected = 0
@State var aCount = 0
var body: some View {
Grid (horizontalSpacing: 0, verticalSpacing: 0) {
ForEach(0..<gridSize, id: \.self) { row in
GridRow{
ForEach(0..<gridSize, id: \.self) { col in
Rectangle()
.foregroundColor(.gray)
.overlay(Text("\(aCount)"))
.border(Color.black)
.bold()
}
}
}
}
}
}
This creates a grid of gridSize x gridsize grey rectangles, so 3x3 in this version
and in a class file I have a fairly simple function that increments an int passed to it by 1 and returns that new value:
func theIncrement(theCount: Int) -> Int {
let theCounter = theCount + 1
return theCounter
}
how do use that function to increment aCount in the inner foreach loop? This does not seem like it should be impossible, and yet, swiftUI is being itself again.
any help is appreciated
|
|
Since you have it marked as an @State property, every time you increment aCount , your View with redraw. Probably not what you want to do in a loop that is just populating the screen.
Instead, in your View 's initializer you could create an array that has a length of gridSize * gridSize (call it, say, matrix or whatever), fill it with your values you want to display, and then inside the inner ForEach , you can access the values like so:
Rectangle()
.foregroundColor(.gray)
.overlay(Text("\(matrix[(row * gridSize) + col])"))
.border(Color.black)
.bold()
|
|
I was think same thing as @roosterboy but changing the ForEach
struct ContentView: View {
@State var gridSize = 3
var body: some View {
Grid (horizontalSpacing: 0, verticalSpacing: 0) {
ForEach(0..<gridSize, id: \.self) { row in
GridRow{
ForEach(1...gridSize, id: \.self) { col in // <- change to start at one to the gridsize
Rectangle()
.foregroundColor(.gray)
.overlay(Text("\(col + (row * gridSize))")) // <- add column count to the row count times grid size
.border(Color.black)
.bold()
}
}
}
}
}
}
|
|
Okay I get how to build a grid. That's easy. But what I need the counter for is so that eventually I can have button 1,1, when clicked, kick off a function that checks the states of buttons 1,2 and 1,0 and take action on those.
I have tried literally everything i can think of to do this, and the only thing I've come up with is an array of structs with the buttons in them, whcih I have, and I need to have the coutner so I can be sure of what button is where so that I know that button at 0,0 is also button[0] in the array.
i have been beating my head against this for over a month and have found zero information anywehre on how to have button a talk to and get state from buttons b and c. So this was the best thing I can manage.
SwiftUI is great for beginners until you want to move past drawing UIs and do more than click a button and pop an alert, or at least that's how i feel right now. In UIKit or even C#, this kind of thing is easy. I just want to do it in SwiftUI and I don't understand why this is hard.
|
|
If I get you right then you want a button that does different action or takes from an array
struct ContentView: View {
let gridSize = 3
let array = [
"index 0",
"index 1",
"index 2",
"index 3",
"index 4",
"index 5",
"index 6",
"index 7",
"index 8",
]
var body: some View {
Grid (horizontalSpacing: 0, verticalSpacing: 0) {
ForEach(0..<gridSize, id: \.self) { row in
GridRow{
ForEach(0..<gridSize, id: \.self) { col in
let buttonNumber = col + (row * gridSize)
Button {
// THIS WILL TAKE AN INDEX NUMBER AND PRINT WHAT IN THE ARRAY
guard buttonNumber < array.count else { return }
print(array[buttonNumber])
// THIS WILL GO TO A METHOD TO RUN SOME OTHER CODE
getButtonTapped(for: buttonNumber)
} label: {
Rectangle()
}
.foregroundColor(.gray)
.overlay(Text("\(buttonNumber)"))
.border(Color.black)
.bold()
}
}
}
}
}
func getButtonTapped(for number: Int) {
switch number {
case 0:
print("Do something for number 0")
case 1:
print("Do something for number 1")
case 2:
print("Do something for number 2")
case 3:
print("Do something for number 3")
case 4:
print("Do something for number 4")
case 5:
print("Do something for number 5")
case 6:
print("Do something for number 6")
case 7:
print("Do something for number 7")
case 8:
print("Do something for number 8")
default:
break
}
}
}
|
|
@NigelGee OMG, that's like 80% of what I've been losing my MIND on.
I can actually now tell what button i'm clicking from WITHIN THE BUTTON
okay, so my next question: i click button 1, but I want that to change the overlay for button say...4, how would I do that?
|
|
Change the oveylay modifiler (in this example) to .overlay(Text("\(array[buttonNumber])")) then in the method change case 1 to array[4] = "changed"
struct ContentView: View {
let gridSize = 3
@State private var array = [
"button 0",
"button 1",
"button 2",
"button 3",
"button 4",
"button 5",
"button 6",
"button 7",
"button 8",
]
var body: some View {
Grid (horizontalSpacing: 0, verticalSpacing: 0) {
ForEach(0..<gridSize, id: \.self) { row in
GridRow{
ForEach(0..<gridSize, id: \.self) { col in
let buttonNumber = col + (row * gridSize)
Button {
getButtonTapped(for: buttonNumber)
} label: {
Rectangle()
}
.foregroundColor(.gray)
.overlay(Text(array[buttonNumber]))
.border(Color.black)
.bold()
}
}
}
}
}
func getButtonTapped(for number: Int) {
switch number {
case 0:
print("Do something for number 1")
case 1:
array[4] = "CHANGED"
case 2:
print("Do something for number 2")
case 3:
print("Do something for number 3")
case 4:
print("Do something for number 4")
case 5:
print("Do something for number 5")
case 6:
print("Do something for number 6")
case 7:
print("Do something for number 7")
case 8:
print("Do something for number 8")
default:
fatalError("No action assigned for buttons after nine")
}
}
}
Note: Change the arrat to be @State as it now look for changes
|
|
Oh wow, that works really well.
like thank you SO much, I think I have a good shot at getting this to work now!
|