I present a SwiftUI View using a UIHostingController with modalPresentationStyle = .overCurrentContext. Inside this root SwiftUI view, I present a .sheet with a custom modifier to make the sheet background transparent.
Minimal Reproducible Code:
import SwiftUI
class SheetViewModel: ObservableObject {
@Published var isPresented: Bool = true
}
struct RootSheetWrapper: View {
@StateObject var viewModel: SheetViewModel
var body: some View {
// Transparent host view acting as the anchor for the sheet
Color.clear
.customTransparentSheet(isPresented: $viewModel.isPresented, height: 400) {
SheetContent()
}
}
}
// Minimal version of my custom sheet extension
extension View {
func customTransparentSheet(
isPresented: Binding,
height: CGFloat,
@ViewBuilder content: @escaping () -> Content
) -> some View {
ZStack {
self
SomeOverlay()
}
self.sheet(isPresented: isPresented) {
content()
.presentationDragIndicator(.hidden)
.applyTransparentBackground()
.presentationDetents([.height(height)])
}
}
}
private extension View {
@ViewBuilder
func applyTransparentBackground() -> some View {
if #available(iOS 16.4, *) {
self.presentationBackground(.clear)
} else {
self.background(Color.clear.ignoresSafeArea())
}
}
}
Sheet Content:
struct SheetContent: View {
var body: some View {
VStack(spacing: 0) {
// This image should sit behind the home indicator
Image(systemName: "star.fill")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(maxWidth: .infinity)
}
// This makes the background transparent, but the bottom safe area
// still clips the Red background/Image above.
// .ignoresSafeArea(.all) // <--- THIS DOES NOT WORK
}
}
I present it like this:
func presentSheet() {
let viewModel = SheetViewModel()
let hostView = RootSheetWrapper(viewModel: viewModel)
let hostingController = UIHostingController(rootView: hostView)
hostingController.modalPresentationStyle = .overCurrentContext
hostingController.view.backgroundColor = .clear
hostingController.modalTransitionStyle = .crossDissolve
self.present(hostingController, animated: true)
}
What I have tried:
Applying .ignoresSafeArea() on the VStack inside SheetContent.
Applying .background(Color.clear, ignoresSafeAreaEdges: .bottom)
I do see the sheet taking up safe area if I provide the height of the content and sheet to be less than the height of the image, is subtracting height of bottom safe area only way? Please help.