young
(rtSwift)
1
I was just trying to use GeometryReader in different places to see its effect. So looks like if there is more than one view inside, it cannot infer the result type.
import SwiftUI
struct ProgressBar: View {
static let height: Length = 8.0
@Binding var progress: CGFloat
@State var isShowing = false
var body: some View {
ZStack(alignment: .leading) {
// Unable to infer complex closure return type; add explicit type to disambiguate
GeometryReader { geometry in
//Protocol 'View' can only be used as a generic constraint because it has Self or associated type requirements
// GeometryReader { (geometry) -> View in
// Consecutive statements on a line must be separated by ';'
// GeometryReader { (geometry) -> some View in
Rectangle()
.foregroundColor(.gray)
.opacity(0.3)
.frame(width: geometry.size.width, height: Self.height)
.frame(width: geometry.size.width, height: Self.height)
Rectangle()
.foregroundColor(.blue)
.frame(width: self.isShowing ? geometry.size.width * self.progress / 100.0 : 0.0, height: Self.height)
.frame(width: self.isShowing ? geometry.size.width * self.progress / 100.0 : 0.0, height: Self.height)
.animation(.linear(duration: 0.6))
}
}
.onAppear { self.isShowing = true }
.cornerRadius(4.0)
}
}
#if DEBUG
struct ProgressBar_Previews: PreviewProvider {
static var previews: some View {
ProgressBar(progress: .constant(25.0))
}
}
#endif
See error messages inside the code at GeometryReader()...
Documentation: Apple Developer Documentation
@frozen struct GeometryReader<Content> where Content : View
init(content: @escaping (GeometryProxy) -> Content)
So I have to somehow tell the compiler that Content is a View here. But I cannot figure out how to do this 
1 Like
It looks like that parameter of GeometryReader.init is supposed to be marked with @ViewBuilder but isn't.
You should be able to work around that by wrapping the body of the closure in an unnecessary stack, like GeometryReader { geometry in VStack { ... } }.
1 Like
GreatApe
(Gustaf Kugelberg)
3
I have had problems with GeometryReader even when it returns just one View, if I also do something else before returning. Like
GeometryReader { proxy in
let x = blabla
return VStack(spacing: x) { ... }
}
In those cases I solved it with putting both lines in a separate function, that potentially also take the proxy as argument.
That's due to a current limitation in Swift where the closure's return type is inferred only if its content is a single expressions.
3 Likes
mayoff
(Rob Mayoff)
5
Another workaround is to introduce this general helper function:
func bind<Value, Answer>(_ value: Value, in body: (Value) throws -> Answer) rethrows -> Answer {
return body(value)
}
Then you can write this:
GeometryReader { proxy in
bind(blabla) { x in
VStack(spacing: x) {
...
}
}
}
2 Likes
filimo
(VictorK)
6
If you place two rectangles in the VStack, the error will be fixed.
var body: some View {
ZStack(alignment: .leading) {
GeometryReader { geometry in
VStack {
Rectangle()
.foregroundColor(.gray)
.opacity(0.3)
.frame(width: geometry.size.width, height: Self.height)
.frame(width: geometry.size.width, height: Self.height)
Rectangle()
.foregroundColor(.blue)
.frame(width: self.isShowing ? geometry.size.width * self.progress / 100.0 : 0.0, height: Self.height)
.frame(width: self.isShowing ? geometry.size.width * self.progress / 100.0 : 0.0, height: Self.height)
.animation(.linear(duration: 0.6))
}
}
}
.onAppear { self.isShowing = true }
.cornerRadius(4.0)
}
young
(rtSwift)
7
The bug is fixed in Xcode 11 Beta 5
Hi Luca and welcome, glad to see SwiftUI developers joining to the SE forums.
This hopefully willChange everything (pun intended).
1 Like