I want to present a search sheet over a map similar to Apple Maps. However, using SwiftUI's default sheet(isPresented:onDismiss:content:)
the background gets scaled which leads to unexpected jumps in the underlying map on sheet dismissal.
Apple Maps:
My app:
The suggested solution from this question makes it possible to prevent the scaling when manually dragging up the view:
The scaling behavior is only present when I present the sheet via the search text's @FocusedState
(run it on a simulator or on device as Xcode previews may not show the keyboard):
import SwiftUI
import MapKit
struct ContentView: View {
@State private var showSheet = true
var body: some View {
Map()
.sheet(isPresented: $showSheet) {
MinimalSearchSheet()
}
}
}
struct MinimalSearchSheet: View {
@State private var searchQuery = ""
@State private var selectedDetent: PresentationDetent = .fraction(0.1)
@FocusState private var isSearchFocused: Bool
var body: some View {
VStack {
HStack {
Image(systemName: "magnifyingglass")
TextField("Search", text: $searchQuery)
.padding(12)
.background(Color.gray.opacity(0.1))
.cornerRadius(8)
.focused($isSearchFocused)
}
.padding()
Spacer()
}
.presentationDetents([.fraction(0.1), .fraction(0.333), .fraction(0.999)], selection: $selectedDetent)
.interactiveDismissDisabled()
.onChange(of: isSearchFocused) {_, focused in
if focused {
selectedDetent = .fraction(0.999)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I assume that it has something to do with the keyboard pushing up the view because I can't set if focused { selectedDetent = .medium }
, the sheet is always returned as .large
. Adding .ignoresSafeArea(.keyboard)
yielded no results.
When implementing a smaller detention to give the keyboard more room, I get the correct behavior when setting the detent, but dismissing it makes the map glitch.
To prevent scaling, you probably need to allow space for the keyboard to be shown in addition to your detent. On an iPhone 16 simulator, there is no scaling with a detent fraction of 0.5:
VStack {
// ...
}
.presentationDetents([.fraction(0.1), .fraction(0.333), .fraction(0.5)], selection: $selectedDetent)
.interactiveDismissDisabled()
.onChange(of: isSearchFocused) {_, focused in
if focused {
selectedDetent = .fraction(0.5)
}
}
The other glitch that you described was the movement of the map as the sheet is swiped away. I found that it helps to apply .ignoresSafeArea(.keyboard)
to the Map
:
Map()
.ignoresSafeArea(.keyboard) // 👈 here
.sheet(isPresented: $showSheet) {
MinimalSearchSheet()
}