Reputation: 155
I am trying to have a sheet with 2 buttons to navigate to different views. This works fine with a NavigationView + NavigationLink. It navigates as expected to another view.
However I am dealing with this:
First I as expected see the presentationBackground:
However then navigating with a NavigationLink leads to a white background:
I am new to swiftui so I may be missing the obvious here. I tried setting both presentationBackground and background on both the destination paramter of the NavigationLink and the content within the new view. Those all seemed to have no affect.
Example Code:
import Foundation
import SwiftUI
struct PlaceHolderView_Demo: View {
@Binding fileprivate var currentSheetOpeningLevel: PresentationDetent
var body: some View {
VStack(alignment: .leading) {
Text("Meow")
}.onAppear {
currentSheetOpeningLevel = PresentationDetent.large
}.background(Color.clear, ignoresSafeAreaEdges: .all)
}
}
struct ContentView: View {
@State private var currentSheetOpeningLevel = PresentationDetent.medium
var body: some View {
NavigationView {
MapView()
.edgesIgnoringSafeArea(.all)
.sheet(isPresented: .constant(true)) {
NavigationView {
InfoSheetView_Demo(currentSheetOpeningLevel: $currentSheetOpeningLevel)
}
.navigationViewStyle(.stack)
.presentationDetents([.medium, .large], selection: $currentSheetOpeningLevel)
.interactiveDismissDisabled(true)
.presentationBackgroundInteraction(.enabled)
.presentationBackground(.ultraThinMaterial)
}
}
.navigationViewStyle(.stack)
}
}
struct InfoSheetView_Demo: View {
@Binding var currentSheetOpeningLevel: PresentationDetent
@State private var searchText = ""
var body: some View {
VStack(alignment: .leading) {
InfoSheetContent(currentSheetOpeningLevel: $currentSheetOpeningLevel).padding()
Spacer()
}
.searchable(text: $searchText, prompt: Text("Search for your Destination"))
}
struct InfoSheetContent: View {
@Binding fileprivate var currentSheetOpeningLevel: PresentationDetent
@Environment(\.isSearching) private var isSearching
@State private var searching: Bool = false
var body: some View {
if !searching {
VStack(alignment: .leading) {
HStack(alignment: .top, spacing: 10) {
Button(action: {}) {
Label("Karte", systemImage: "map")
.labelStyle(DefaultLabelStyle())
.frame(maxWidth: .infinity)
}
.buttonStyle(.borderedProminent)
.controlSize(.large)
NavigationLink(destination: PlaceHolderView_Demo(currentSheetOpeningLevel: $currentSheetOpeningLevel)) {
Label("Mitnehmen", systemImage: "figure.wave")
.labelStyle(DefaultLabelStyle())
.frame(maxWidth: .infinity)
}
.buttonStyle(.bordered)
.controlSize(.large)
}
.padding()
}
.background(.thinMaterial)
.frame(maxWidth: .infinity, maxHeight: 120)
.cornerRadius(15)
}
}
}
}
struct ContentView_Demo_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Upvotes: 1
Views: 317
Reputation: 150
The answer here describes what the problem is: SwiftUI is injecting a View that has a systemBackground color and which we cannot control from SwiftUI.
You can use Introspect to work around the problem. Introspect allows you to find that view and manually change the color to .clear
and also remove the shadow. Note that the push and pop animations do not work well with a clear background - so your result will look like this.
I worked around this problem by using NavigationTransitions to change the transition to a cross fade. The result looks fine:
Here is the source for the cross fade View. You can comment in the code and remove the .navigationTransition
if you prefer the push/pop slide effect.
import MapKit
import NavigationTransitions
import SwiftUI
import SwiftUIIntrospect
struct ContentView: View {
@State var navigationPath: [SubSheet] = []
var body: some View {
Map(initialPosition: .region(.applePark))
.ignoresSafeArea(.all)
.sheet(isPresented: .constant(true)) {
NavigationStack(path: $navigationPath) {
VStack {
Text("Test")
NavigationLink(
"Activate SubSheet", value: SubSheet.subSheetOne)
}
.navigationDestination(for: SubSheet.self) { something in
Text("SubSheet")
.introspect(
.navigationStack, on: .iOS(.v18),
scope: .ancestor
) { something in
let allsubviews = something.view.allSubViews
allsubviews.forEach { view in
if view.backgroundColor == .systemBackground
&& view.debugDescription.contains(
"NavigationStackHostingController")
{
// We found the child view that has the systemBackground we don't want, so we remove it.
view.backgroundColor = nil
}
// if you want to use the push/pop transition, you can comment in
// this code to remove the shadow too.
/*
if view.backgroundColor != .black && view.backgroundColor?.cgColor.alpha == 0.1 {
print("changing from \(view.backgroundColor)")
view.backgroundColor = nil
}
*/
}
}
.navigationTitle("SubSheet")
}
}
.navigationTransition(.fade(.cross)) // remove this if you really want the push/pop slide effect
.scrollContentBackground(.hidden)
.backgroundStyle(.clear)
.presentationDetents([.fraction(0.33)])
.presentationBackgroundInteraction(
.enabled(upThrough: .fraction(0.33))
)
.presentationBackground(.ultraThickMaterial)
}
}
}
enum SubSheet: Hashable {
case subSheetOne
}
extension UIView {
/// Retrieving All Subviews from a UIView
fileprivate var allSubViews: [UIView] {
return subviews.flatMap { [$0] + $0.allSubViews }
}
}
extension MKCoordinateRegion {
/// Apple Mark Region
static var applePark: MKCoordinateRegion {
let center = CLLocationCoordinate2D(
latitude: 37.334606, longitude: -122.009102)
return .init(
center: center, latitudinalMeters: 10000, longitudinalMeters: 10000)
}
}
#Preview {
ContentView()
}
Upvotes: 0