Go to a specific View with Button

Hello World ! I figured out some issues in my code : I want to got to a specific view after pressing a button. In fact I cannot use the traditional NavigationLink because I need to do some stuff before. It's like a dismiss function but if I use the

@Environment(\.dismiss) var dismiss

it goes to the wrong view. So there is my code :

Button("Save"){
                print("Save")
                checkCondition()
                if !showAlert{
                    addToBase()
                    showAchievement = true
                    Timer.scheduledTimer(withTimeInterval: 1.01, repeats: false) { _ in
                        showExhibitView = true
                        
                    }
                    
                }
            }

So after the timer I need to display the ExhibitView. Plz Help me !

Answered by Claude31 in 769407022

You don't show a lot of code, so hard to say.

But you should call ExhibitView() when showExhibitView is true.

Here is a simplified example of such code.

struct ExhibitView: View {
    
    var body: some View {
        Text("I show exhibit")
    }
}

struct ContentView: View {
    @State var showExhibitView = false
    
    var body: some View {

        Button("Save"){
            print("Save")
            Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { _ in.  // 3 s to have time to notice
                    showExhibitView = true
                }
            }

        if showExhibitView {
            ExhibitView()
        }
    }
    
}

If you replace

            showExhibitView = true

with

            showExhibitView.toggle()

You see ExhibitView appear and disappear.

If you want something that behaves more like a NavigationLink, do it with Bindings:

struct FirstView: View {
    @Binding var showExhibitView : Bool
    
    var body: some View {
        Button("Save"){
            print("Save")
            Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { _ in
                showExhibitView = true
                }
            }
    }
}

struct ExhibitView: View {
    @Binding var showExhibitView : Bool

    var body: some View {
        
        Button("Return"){
                showExhibitView = false
            }
        Text("I show exhibit")
    }
}

struct ContentView: View {
    @State var showExhibitView = false
    
    var body: some View {

        if showExhibitView {
            ExhibitView(showExhibitView: $showExhibitView)
        } else {
            FirstView(showExhibitView: $showExhibitView)
        }
    }
    
}
Accepted Answer

You don't show a lot of code, so hard to say.

But you should call ExhibitView() when showExhibitView is true.

Here is a simplified example of such code.

struct ExhibitView: View {
    
    var body: some View {
        Text("I show exhibit")
    }
}

struct ContentView: View {
    @State var showExhibitView = false
    
    var body: some View {

        Button("Save"){
            print("Save")
            Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { _ in.  // 3 s to have time to notice
                    showExhibitView = true
                }
            }

        if showExhibitView {
            ExhibitView()
        }
    }
    
}

If you replace

            showExhibitView = true

with

            showExhibitView.toggle()

You see ExhibitView appear and disappear.

If you want something that behaves more like a NavigationLink, do it with Bindings:

struct FirstView: View {
    @Binding var showExhibitView : Bool
    
    var body: some View {
        Button("Save"){
            print("Save")
            Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { _ in
                showExhibitView = true
                }
            }
    }
}

struct ExhibitView: View {
    @Binding var showExhibitView : Bool

    var body: some View {
        
        Button("Return"){
                showExhibitView = false
            }
        Text("I show exhibit")
    }
}

struct ContentView: View {
    @State var showExhibitView = false
    
    var body: some View {

        if showExhibitView {
            ExhibitView(showExhibitView: $showExhibitView)
        } else {
            FirstView(showExhibitView: $showExhibitView)
        }
    }
    
}

Hey thanks for answering @Claude31 but that does not fit with I what I want. There is the all code of the page and a brief resumé of the idea. It's and AddView called AddExhibView to implement new element in a Database, so I want after pressing the save button to show the ListView called ExhibitView where I display all the data. There is the code :


import SwiftUI
import CoreData

struct AddExhibView: View {
    @Environment(\.dismiss) var dismiss
    @Environment(\.managedObjectContext) private var viewContext
    
    @State private var name: String = ""
    @State private var info: String = ""
    @State private var isOnline: Bool = false
    @State private var startDate: Date = Date()
    @State private var endDate: Date = Date()
    @State private var contactBuyer = false
    
    
    @State private var showAlert: Bool = false
    
    @State private var alertMessage: String = "Il en manque ..."
    
    //MARK: Drag&Drop Stuff
    @State var firstImage =  NSImage(named: "image")
    @State var firstUrl: URL?
    

    @State var secondImage =  NSImage(named: "image")
    @State var secondUrl: URL?
    
    @State var thirdImage =  NSImage(named: "image")
    @State var thirdUrl: URL?
    
    //MARK: Aheviement Stuff
    @State private var showAchievement: Bool = false
    let achievement =  Achievement(title: "Succès", description: "L'élément a été ajouté avec succès")
    
    @State private var showExhibitView: Bool = false
    
    
    var body: some View {
        
        HStack{
            DropImage(image: $firstImage, url: $firstUrl)
            
            if firstImage != nil {
                DropImage(image: $secondImage, url: $secondUrl)
                
                if secondImage != nil{
                    DropImage(image: $thirdImage, url: $thirdUrl)
                }
                
            }
        }
        
        Form{
            VStack{
                TextField("Titre", text: $name)
                    .textFieldStyle(.roundedBorder)
                
                HStack{
                    
                    DatePicker("Début", selection: $startDate)
                    DatePicker("Fin", selection: $endDate)
                    Spacer()
                    Toggle("Informer les acheteurs", isOn: $contactBuyer)
                    Toggle("Mettre en ligne", isOn: $isOnline)
                    
                }
            
                
                HStack{
                    VStack{
                        Text("Description")
                        Spacer()
                    }
                    
                    TextEditor(text:$info)
                        .textFieldStyle(.roundedBorder)
                }
                
            }
            
            
                
            
        }
        .padding()
        
        //MARK: Save
        HStack{
            Button("Validez"){
                print("validez")
                checkCondition()
                if !showAlert{
                    addToBase()
                    showAchievement = true
                    Timer.scheduledTimer(withTimeInterval: 1.01, repeats: false) { _ in
                        showExhibitView = true
                        
                    }
                    
                }
            }
            .alert(isPresented: $showAlert){
                Alert(title: Text("Oops ?"),
                        message: Text(alertMessage))
            }
            .sheet(isPresented: $showAchievement) {
                AchievementPopView(achievement: achievement, isPresented: $showAchievement)
            }
            
        }
        .padding()
        
    
        if showExhibitView{
            ExhibitView()
        }
    
        
    }
    
    private func checkCondition(){
        if name == "" || firstImage == nil {
            showAlert = true
            return
        }
    }
    
    private func addToBase(){
        
        let firstImageData = jpegDataFrom(image: firstImage!)
        
        
        if secondImage != nil && thirdImage == nil{
            let secondImageData = jpegDataFrom(image: secondImage!)
            DataController().addExhibit(name: name,
                                        info: info,
                                        firstImage: firstImageData,
                                        secondImage: secondImageData,
                                        thirdImage:nil,
                                        startDate: startDate,
                                        endDate: endDate,
                                        isOnline: isOnline,
                                        contactBuyer: contactBuyer,
                                        context:viewContext)
            print("2")
            return 
            
           
        } 
        
        if secondImage != nil && thirdImage != nil {
            let secondImageData =  jpegDataFrom(image: secondImage!)
            let thirdImageData = jpegDataFrom(image: thirdImage!)
            DataController().addExhibit(name: name,
                                        info: info,
                                        firstImage: firstImageData,
                                        secondImage: secondImageData,
                                        thirdImage:thirdImageData,
                                        startDate: startDate,
                                        endDate: endDate,
                                        isOnline: isOnline,
                                        contactBuyer: contactBuyer,
                                        context:viewContext)
            print("3")
            return
        }
        
        DataController().addExhibit(name: name,
                                    info: info,
                                    firstImage: firstImageData,
                                    secondImage: nil,
                                    thirdImage:nil,
                                    startDate: startDate,
                                    endDate: endDate,
                                    isOnline: isOnline,
                                    contactBuyer: contactBuyer,
                                    context:viewContext)
        print("1")
        return
        
          
    }

}

@Claude31 in fact it can might works. I will try

@Claude31 so adapted your code to my project and I tested. Well done it's working. Thanks a lot. I am not familiar with such binding variables. Thanks for helping me out.

@Binding may seem complex but in fact pretty simple. And extremely important in SwiftUI. It is somehow equivalent to inout for a parameter.

  • You have a State var in a view 1.
  • you want to change this var in another view. 2
  • You declare a Binding var in View 2 of the correct type, but not assigning value
  • When you call view 2 from View 1, you pass the State var as parameter
  • that will initialize the Binding var in View 2
  • If you change value in View 2, that will propagate the change to State var (in fact you pass a reference of the State var).

Hope that's clearer. Good continuation.

Go to a specific View with Button
 
 
Q