I try to create a custom ViewModifier similar to SwiftUI’s .sheet modifier.
When I try to make a NavigationView spring from bottom, the frame of the view just glitched over safearea. The frame looks as if adjust to the safearea when the view moves from bottom to top.
Anyone knows maybe how to constrain the view frame inside the navigation view to avoid this?
Here is what happened. When click the plus button, the SwiftUI .sheet modifier shows up. Custom popup shows up when pressing the gear button.
Problem gif recording here
Here is code of the custom popup view.
struct SettingsView: View {
@Binding var showingSelf: Bool
@Binding var retryWrongCards: Bool
var body: some View {
GeometryReader { geometry in
NavigationView {
List {
Section {
Toggle(isOn: $retryWrongCards) {
Text("Retry Wrong Cards")
}
}
}
.animation(nil)
.navigationViewStyle(StackNavigationViewStyle())
.listStyle(GroupedListStyle())
.navigationBarTitle("Settings")
.navigationBarItems(trailing: Button("Done") {
self.showingSelf = false
})
}
}
}
}
Here’s the code of custom modifier
struct Popup<T: View>: ViewModifier {
let popup: T
let isPresented: Bool
init(isPresented: Bool, @ViewBuilder content: () -> T) {
self.isPresented = isPresented
popup = content()
}
func body(content: Content) -> some View {
content
.overlay(popupContent())
}
@ViewBuilder private func popupContent() -> some View {
GeometryReader { geometry in
if isPresented {
popup
.animation(.spring())
.transition(.offset(x: 0, y: geometry.belowScreenEdge))
.frame(width: geometry.size.width, height: geometry.size.height)
}
}
}
}
private extension GeometryProxy {
var belowScreenEdge: CGFloat {
UIScreen.main.bounds.height - frame(in: .global).minY
}
}
2
Answers
It seems your animation does exactly what a sheet does. I would just replace it with that. You can easily present a sheet on top of a sheet.
Edit
After you posted your ViewModifier code, it seems the only difference is the animation type and the size of the popup.
After debugging and trying many changes, I was already preparing a mini-project to file a SwiftUI bug for Apple. In the end, it was not necessary and we have a simple solution 🥳!!
TLDR; your
SettingsView
does not correctly initialise theNavigationView
.The modifier
.navigationViewStyle(StackNavigationViewStyle())
has to be applied onto theNavigationView
and not inside it (in contrast tonavigationBarTitle
ornavigationBarItems
which only work when put inside theNavigationView
):After this change your custom sheet modifier behaves for me identically as the regular
.sheet
modifier! Great work!Philipp