So I have a button as shown below:
private var getStartedButton: some View {
Button {
showGetStartedSheet.toggle()
} label: {
Text("Get Started")
}
.sheet(isPresented: $showGetStartedSheet) {
LoginUserSheetView()
.presentationDetents([.fraction(0.70), .large])
}
}
Which opens the LoginUserSheetView()
view and has the following function inside:
private var userCreateAccount: some View {
VStack(alignment: .center) {
Text("New MapGliders? User register")
.sheet(isPresented: $showUserRegisterSheet) {
RegisterUserSheetView()
.presentationDetents([.fraction(0.70), .large])
}
}
}
The above code, then opens another sheet which presents the following code:
private var appleButton: some View {
Button {
// Hello
} label: {
HStack(alignment: .firstTextBaseline) {
Image(systemName: "applelogo")
Text("Hello")
}
}
}
The above code (lots has been removed) produces the following output:
https://im4.ezgif.com/tmp/ezgif-4-4ecfdb6d55.gif
As you can see the video above, the second sheet opens on top of the old sheet, I would like the sheet to be overwritten or create a navigation on a single sheet.
Does anyone know how I can close LoginUserSheetView()
when RegisterUserSheetView()
is opened? or how could I make the sheet be overwritten or even use a navigation to navigate to RegisterUserSheetView()
when on the LoginUserSheetView()
is opened.
CodePudding user response:
The first option is to use sheet(item:)
. But this does dismiss the sheet and they makes it reappear with the new value
struct DynamicOverlay: View {
@State var selectedOverlay: OverlayViews? = nil
var body: some View {
VStack{
Text("hello there")
Button("first", action: {
selectedOverlay = .first
})
}
.sheet(item: $selectedOverlay){ passed in
passed.view($selectedOverlay)
}
}
enum OverlayViews: String, Identifiable{
var id: String{
rawValue
}
case first
case second
@ViewBuilder func view(_ selectedView: Binding<OverlayViews?>) -> some View{
switch self{
case .first:
ZStack {
Color.blue
.opacity(0.5)
Button {
selectedView.wrappedValue = .second
} label: {
Text("Next")
}
}
case .second:
ZStack {
Color.red
.opacity(0.5)
Button("home") {
selectedView.wrappedValue = nil
}
}
}
}
}
}
The second option doesn't have the animation behavior but required a small "middle-man" View
import SwiftUI
struct DynamicOverlay: View {
@State var selectedOverlay: OverlayViews = .none
@State var presentSheet: Bool = false
var body: some View {
VStack{
Text("hello there")
Button("first", action: {
selectedOverlay = .first
presentSheet = true
})
}
.sheet(isPresented: $presentSheet){
//Middle-main
UpdatePlaceHolder(selectedOverlay: $selectedOverlay)
}
}
enum OverlayViews{
case first
case second
case none
@ViewBuilder func view(_ selectedView: Binding<OverlayViews>) -> some View{
switch self{
case .first:
ZStack {
Color.blue
.opacity(0.5)
Button {
selectedView.wrappedValue = .second
} label: {
Text("Next")
}
}
case .second:
ZStack {
Color.red
.opacity(0.5)
Button("home") {
selectedView.wrappedValue = .none
}
}
case .none:
EmptyView()
}
}
}
//Needed to reload/update the selected item on initial presentation
struct UpdatePlaceHolder: View {
@Binding var selectedOverlay: OverlayViews
var body: some View{
selectedOverlay.view($selectedOverlay)
}
}
}
You can read a little more on why you need that intermediate view here SwiftUI: Understanding .sheet / .fullScreenCover lifecycle when using constant vs @Binding initializers