admin管理员组

文章数量:1390717

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.

Edit

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.

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.

Edit

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.

Share Improve this question edited Mar 14 at 13:35 Sweeper 278k23 gold badges242 silver badges397 bronze badges Recognized by Mobile Development Collective asked Mar 14 at 10:21 DoskoDosko 601 silver badge6 bronze badges 1
  • You can trigger a keyboard on a simulator using cmd+K btw and it shows that keyboard is definitely a problem here – Kiryl Famin Commented Mar 14 at 10:35
Add a comment  | 

2 Answers 2

Reset to default 3

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) // 

本文标签: iosPrevent scaling of background view in SwiftUI when sheet gets presented by FocusStateStack Overflow