问题
I am trying to create a hexagon grid using swiftUI on Xcode. To loop over the creation of the individual hexagons I am using a foreach loop. However I came Across an error when creating a function that creates a column of hexagons:
private func makeCol(C: Int, Bump:Int) -> some View {
return ZStack {
ForEach(-5...5, id: \.self) {Ynumber in
self.hexagon(
x: (ThreeRooted * self.L * Double(C)) + self.centerWidth,
y: (ThreeRooted * self.L * Double(Ynumber)) + self.centerHeight + (ThreeRootedOverTwo * self.L * Bump))
.stroke(Color.red, lineWidth: CGFloat(self.L/4.0))
}
}
}
Error: The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions.
To get around this I extracted my location fields in separate variables. However, this gave another error:
private func makeCol(C: Int, Bump:Int) -> some View {
return ZStack {
ForEach(-5...5, id: \.self) {Ynumber in
let xPlot = (ThreeRooted * self.L * Double(C)) + self.centerWidth
let yPlot = (ThreeRooted * self.L * Double(Ynumber)) + self.centerHeight + (ThreeRootedOverTwo * self.L * Bump)
self.hexagon(
x: xPlot,
y: yPlot)
.stroke(Color.red, lineWidth: CGFloat(self.L/4.0))
}
}
}
Error: Unable to infer complex closure return type; add explicit type to disambiguate.
How do I give this loop an explicit type?
回答1:
ForEach is a structure that computes views on demand from an underlying collection of identified data, NOT a loop.
How to create hexagonal grid? Below is one possible approach where I tried to show you how to use ForEach
and SwiftUI declarative syntax.
import SwiftUI
struct Hexagon: Shape {
func path(in rect: CGRect) -> Path {
Path { (path) in
path.move(to: .init(x: rect.midX, y: rect.minY))
path.addLine(to: .init(x: rect.maxX, y: (rect.minY + rect.midY) / 2 ))
path.addLine(to: .init(x: rect.maxX, y: (rect.maxY + rect.midY) / 2 ))
path.addLine(to: .init(x: rect.midX, y: rect.maxY))
path.addLine(to: .init(x: rect.minX, y: (rect.maxY + rect.midY) / 2 ))
path.addLine(to: .init(x: rect.minX, y: (rect.minY + rect.midY) / 2 ))
path.closeSubpath()
}
}
}
struct ContentView: View {
var body: some View {
VStack(spacing: -10) {
ForEach(0 ..< 3) { j in
HStack(spacing: 5) {
ForEach(0 ..< 4) { i in
Hexagon()
.fill(Color.yellow)
.overlay(
Hexagon()
.stroke(Color.red, lineWidth: 5)
)
.frame(width: 50, height: 60)
}
}
HStack(spacing: 5) {
ForEach(0 ..< 3) { i in
Hexagon()
.stroke(Color.blue, lineWidth: 5)
.frame(width: 50, height: 60)
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
and here is the result
Spacing and frame parameters are fixed here for simplicity, you are better to calculate proper numbers.
init(Range<Int>, content: (Int) -> Content)
Available when Data is Range, ID is Int, and Content conforms to View.
You tried to use
init(Data, id: KeyPath<Data.Element, ID>, content: (Data.Element) -> Content)
Available when Content conforms to View.
and finally we don't have any idea what type returns your hexagon function, it could be Shape, but Shape is protocol, and that could make your trouble. If it is Shape, try define return type as some Shape.
Yes, compiler error reporting is still not very usable with SwiftUI
回答2:
How do I give this loop an explicit type?
ForEach(-5...5, id: \.self) { (Ynumber) -> _ExplicitType_ in
...
return self.hexagon(
...
)
}
来源:https://stackoverflow.com/questions/60230457/how-to-disambiguate-a-foreach-loop-in-xcode-with-swiftui