I have an overlay in my SwiftUI view as follows (for simplicity purpose, I have a view with plain blue color in the code below):
.overlay(alignment: .bottom, content: {
showMenu ? Color.blue.frame(height: 150) : nil
})
My problem is that it does not respect safe area in landscape mode and I see no way to customize it so that the overlay does not cross dynamic island on iPhone 14/15 pro. It is okay to target iOS 16 and above if that simplifies things.
Do you mean, the overlay is not extending into the safe area?
A pre-requisite for this to be possible is that the view the overlay is being applied to must be in contact with the safe area insets. Then, just apply .ignoresSafeArea()
before applying the .frame
:
EDIT If you only want it to respect the side insets, but still ignore the bottom insets, then you need to specify the edges
for .ignoreSafeArea()
EDIT2 deleted
EDIT3 I managed to reproduce the issue that you were describing, where it wasn't working when the overlay contains a horizontal ScrollView
.
To fix, .clipped()
needs to be applied to the ScrollView
. This prevents it from overflowing into the safe areas. This tip comes from the answer to iOS SwiftUI: ScrollView ignore top safe area (you are welcome to give it an upvote).
If you only want the background color to ignore the bottom safe area insets, but not the actual content of the overlay, then .ignoresSafeArea(edges: .bottom)
should be moved to the background color instead.
let loremIpsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
@State private var showMenu = true
private var menu: some View {
ScrollView(.horizontal) {
HStack {
Text(loremIpsum)
.font(.title)
.fixedSize(horizontal: false, vertical: true)
}
.frame(maxWidth: 900, maxHeight: .infinity, alignment: .top)
}
.clipped()
.background { Color.blue }
.ignoresSafeArea(edges: .bottom)
.frame(height: 150)
}
var body: some View {
VStack(spacing: 20) {
Text(loremIpsum)
Text(loremIpsum)
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.overlay(alignment: .bottom) {
showMenu ? menu : nil
}
}