I am at the moment writing a customized backside sheet to make use of in SwiftUI which makes use of UISheetPresentationController
. I’ve created a struct that conforms to UIViewRepresentable
. Within the updateUIView
methodology, I am wrapping a SwiftUI view in a UIHostingController
then presenting the view controller as a sheet.
func updateUIView(_ uiView: UIView, context: Context) {
let viewController = UIViewController()
let hostingController = UIHostingController(rootView: content material)
viewController.addChild(hostingController)
viewController.view.addSubview(hostingController.view)
hostingController.view.backgroundColor = .clear
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
viewController.view.backgroundColor = .clear
viewController.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
hostingController.view.topAnchor.constraint(equalTo: viewController.view.topAnchor, constant: 20),
hostingController.view.leadingAnchor.constraint(equalTo: viewController.view.leadingAnchor, constant: 20),
hostingController.view.trailingAnchor.constraint(equalTo: viewController.view.trailingAnchor, constant: -20),
hostingController.view.bottomAnchor.constraint(equalTo: viewController.view.bottomAnchor, constant: -20)
])
hostingController.didMove(toParent: viewController)
if let sheetController = viewController.presentationController as? UISheetPresentationController {
sheetController.detents = detents
sheetController.largestUndimmedDetentIdentifier = .massive
sheetController.prefersScrollingExpandsWhenScrolledToEdge = false
sheetController.prefersEdgeAttachedInCompactHeight = true
sheetController.widthFollowsPreferredContentSizeWhenEdgeAttached = true
}
viewController.presentationController?.delegate = context.coordinator
if isPresented {
uiView.window?.rootViewController?.current(viewController, animated: true)
} else {
uiView.window?.rootViewController?.dismiss(animated: true)
}
}
I’ve modified the code in order that the sheet has a transparent background in order that the SwiftUI view appears to be like prefer it’s floating.
Nevertheless, whenever you begin to swipe down on the sheet you begin to see the shadow from the sheet.
As you possibly can see there’s a clear dividing line the place there’s an additional shadow onto of the dimmed background.
I’ve seemed by means of the view hierarchy and it seems to not be associated to the internet hosting controller or the view controller. I’ve tried adjusting properties comparable to layer.shadowColor
on the sheetController however most of these properties are nil. Does anybody know take away the shadow or another appropriate work round for it?
EDIT: The minimal reproducible instance.
struct SheetPresentationForSwiftUI: UIViewRepresentable the place Content material: View {
@Binding var isPresented: Bool
let onDismiss: (() -> Void)?
let detents: [UISheetPresentationController.Detent]
let content material: Content material
init(
_ isPresented: Binding,
onDismiss: (() -> Void)? = nil,
detents: [UISheetPresentationController.Detent] = [.medium()],
@ViewBuilder content material: () -> Content material
) {
self._isPresented = isPresented
self.onDismiss = onDismiss
self.detents = detents
self.content material = content material()
}
func makeUIView(context: Context) -> UIView {
let view = UIView()
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
let viewController = UIViewController()
let hostingController = UIHostingController(rootView: content material)
viewController.addChild(hostingController)
viewController.view.addSubview(hostingController.view)
hostingController.view.backgroundColor = .clear
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
viewController.view.backgroundColor = .clear
viewController.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
hostingController.view.topAnchor.constraint(equalTo: viewController.view.topAnchor),
hostingController.view.leadingAnchor.constraint(equalTo: viewController.view.leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: viewController.view.trailingAnchor),
hostingController.view.bottomAnchor.constraint(equalTo: viewController.view.bottomAnchor)
])
hostingController.didMove(toParent: viewController)
hostingController.view.sizeToFit()
if let sheetController = viewController.presentationController as? UISheetPresentationController {
sheetController.detents = [.medium()]
sheetController.largestUndimmedDetentIdentifier = .massive
sheetController.prefersGrabberVisible = true
sheetController.prefersScrollingExpandsWhenScrolledToEdge = false
sheetController.prefersEdgeAttachedInCompactHeight = true
sheetController.widthFollowsPreferredContentSizeWhenEdgeAttached = true
}
viewController.presentationController?.delegate = context.coordinator
if isPresented {
uiView.window?.rootViewController?.current(viewController, animated: true)
} else {
uiView.window?.rootViewController?.dismiss(animated: true)
}
}
func makeCoordinator() -> Coordinator {
Coordinator(isPresented: $isPresented, onDismiss: onDismiss)
}
class Coordinator: NSObject, UISheetPresentationControllerDelegate {
@Binding var isPresented: Bool
let onDismiss: (() -> Void)?
init(isPresented: Binding, onDismiss: (() -> Void)? = nil) {
self._isPresented = isPresented
self.onDismiss = onDismiss
}
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
isPresented = false
if let onDismiss = onDismiss {
onDismiss()
}
}
}
}
struct SheetWithDetentsViewModifier: ViewModifier the place SwiftUIContent: View {
@Binding var isPresented: Bool
let onDismiss: (() -> Void)?
let detents: [UISheetPresentationController.Detent]
let swiftUIContent: SwiftUIContent
init(isPresented: Binding, detents: [UISheetPresentationController.Detent] = [.medium()] , onDismiss: (() -> Void)? = nil, content material: () -> SwiftUIContent) {
self._isPresented = isPresented
self.onDismiss = onDismiss
self.swiftUIContent = content material()
self.detents = detents
}
func physique(content material: Content material) -> some View {
ZStack {
SheetPresentationForSwiftUI($isPresented,onDismiss: onDismiss, detents: detents) {
swiftUIContent
}
.fixedSize()
content material
}
}
}
extension View {
func sheetWithDetents(
isPresented: Binding,
detents: [UISheetPresentationController.Detent] = [.medium()],
onDismiss: (() -> Void)? = nil,
content material: @escaping () -> Content material) -> some View the place Content material : View {
modifier(
SheetWithDetentsViewModifier(
isPresented: isPresented,
detents: detents,
onDismiss: onDismiss,
content material: content material)
)
}
}
struct TestView: View {
@State var showSheet = false
var physique: some View {
NavigationStack {
VStack {
Textual content("Faucet me")
.onTapGesture {
showSheet = true
}
}
}.sheetWithDetents(isPresented: $showSheet) {
Textual content("Hey")
.body(maxWidth: .infinity, maxHeight: .infinity)
.padding()
.background(
RoundedRectangle(cornerRadius: 40)
.fill(Materials.regularMaterial)
).padding()
}
}
}
#Preview {
TestView()
}