In SwiftUI, I found that adding a blur to some page content which has a ScrollView breaks the layout by adding some unexpected inset at the top of the ScrollView. I have made a minimal reproducible example as follows
import SwiftUI
struct ContentView: View {
@State private var isActive = false
var body: some View {
ZStack {
ScrollView {
VStack {
Rectangle()
.fill(.red)
.frame(height: 200)
Rectangle()
.fill(.orange)
.frame(height: 200)
Rectangle()
.fill(.blue)
.frame(height: 200)
Rectangle()
.fill(.purple)
.frame(height: 200)
Rectangle()
.fill(.yellow)
.frame(height: 200)
Button("Click me") {
isActive = true
}
}
}
if isActive {
Color.clear
.background(.black.opacity(0.1))
.contentShape(Rectangle())
.onTapGesture {
isActive = false
}
.border(.orange)
}
}
.blur(radius: isActive ? 10 : 0)
}
}
#Preview {
ContentView()
}
To see the issue in action, run the app, scroll down to activate the overlay. Next, tap on the status bar to scroll all the way to the top. Tapping on the overlay deactivates it, but the ScrollView is now offset downwards by about 20px. It seems this issue does not occur if no blur is applied to the content.
Does anyone know what is causing this? Is this a bug in SwiftUI or am I doing something wrong? I have observed this issue in iOS 17.5 and the iOS 18 beta