Looks like there is some interference going on.
I have found two workaround-solutions, it depends on what your desired effect is.
Solution 1
Idea: Using ZStack
so that ScrollView
and your header don't interfere.
struct ContentView: View {
@State var largeHeader = true
var body: some View {
ZStack {
ScrollView {
VStack {
ForEach(0..<3) { i in
Text("Content(i)")
.padding()
}
}
.background(GeometryReader { geometryProxy -> Color in
DispatchQueue.main.async {
largeHeader = geometryProxy.frame(in: .named("1")).minY >= 0
}
return Color.clear
})
}
.coordinateSpace(name: "1")
.offset(y: largeHeader ? 100 : 60)
VStack {
VStack {
Spacer()
Text("HEADER")
.padding()
Divider()
}
.frame(maxWidth: .infinity)
.frame(height: largeHeader ? 140 : 100)
.background(Color.white)
Spacer()
}
.edgesIgnoringSafeArea(.all)
}
.animation(.default)
}
}
The header of this one would always change the height, no matter how large the content-height is.
Solution 2
Idea: Only change header height when there is enough content to scroll.
Solution:
Finding out the height of the scrollview-content.
struct ContentView: View {
@State var largeHeader = true
@State var scrollViewScrollable = false
var body: some View {
VStack {
Text("HEADER").padding(.vertical, largeHeader ? 30 : 10)
Divider()
ScrollView {
VStack {
ForEach(0..<3) { i in
Text("Content(i)")
.padding()
}
}
.background(GeometryReader { geometryProxy -> Color in
if scrollViewScrollable {
DispatchQueue.main.async {
largeHeader = geometryProxy.frame(in: .named("1")).minY >= 0
}
}
return Color.clear
})
.background(
GeometryReader { proxy in
Color.clear.onAppear {
scrollViewScrollable = proxy.frame(in: .named("1")).size.height >= UIScreen.main.bounds.size.height - 100
}
}
)
}
.coordinateSpace(name: "1")
}
.animation(.default)
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…