简体   繁体   English

当环境对象更新导致同一视图重新加载时,如何导航到另一个 SwiftUI 视图

[英]How do I navigate to another SwiftUI View when an Environment Object update is causing the same view to reload

What I'm trying to achieve : I'm a new SwiftUI developer.我想要实现的目标:我是一名新的 SwiftUI 开发人员。 I'm trying to build a simple Address Book app.我正在尝试构建一个简单的地址簿应用程序。 I have three views:我有三个看法:

  1. ContentView - The main view which contains all contacts in a List View with an Add Contact ('+') and Edit button at the top of the Navigation View ContentView - 包含列表视图中所有联系人的主视图,导航视图顶部有一个添加联系人 ('+') 和编辑按钮
  2. AddContact View - which has a "Name" and "Email" text field and a "Submit" button AddContact View - 它有一个“姓名”和“电子邮件”文本字段以及一个“提交”按钮
  3. DisplayContactDetails View - not relevant to this question. DisplayContactDetails 视图 - 与此问题无关。

I've created an Environment Object "myContacts" which is an array of "Contact" objects and passed it in the ContentView to keep track of all contacts in the Address Book我创建了一个环境对象“myContacts”,它是一个“联系人”对象数组,并将其传递到 ContentView 中以跟踪地址簿中的所有联系人

When the user navigates to AddContact View, adds a name and email and submits, I'd like the Environment Object "myContacts" to be updated and for the user to be navigated back to ContentView so they can see the Address Book with the new contact included.当用户导航到 AddContact 视图,添加姓名和电子邮件并提交时,我希望更新环境对象“myContacts”,并让用户导航回 ContentView,以便他们可以看到带有新联系人的地址簿包括。

Problem :问题

When the user presses "Submit" on AddContact View, it correctly invokes a navigation link I've created to send the user back to ContentView.当用户在 AddContact 视图上按下“提交”时,它会正确调用我创建的导航链接以将用户发送回 ContentView。 But because the Environment Object "myContacts" has also been updated by submit, it immediately navigates back from ContentView to AddContact View again.但是因为环境对象“myContacts”也被提交更新,它立即再次从 ContentView 导航回 AddContact View。 So it appears to be executing the Navigation Link first but then reloading AddContact View due to the refresh of myContacts.因此,它似乎首先执行导航链接,然后由于 myContacts 的刷新而重新加载 AddContact 视图。

Code - Content view :代码 - 内容视图

    struct ContentView: View {
    
    @EnvironmentObject var myContacts: Contacts
    @State var isAddButtonPressed: Bool = false
    
    var body: some View {
        
        NavigationView{
           
            List {
                
                ForEach(myContacts.contacts) { item in
                    
                    NavigationLink(
                          //Display items and send user to DisplayContactDetails

                        })
                    
                }
            
            }
            .navigationBarTitle("Address Book")
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading){
                    
                    Button(action: {
                        isAddButtonPressed.toggle()
                    }, label: {
                        
                       NavigationLink(
                        destination: AddContactView(),
                        isActive: $isAddButtonPressed,
                        label: {
                            Image(systemName: "plus")
                        })
                        
                    })
                }
                ToolbarItem(placement: .navigationBarTrailing){
                    EditButton()
                }
                
                
            }
        }
    }
    
}

Code - AddContactView代码 - AddContactView

struct AddContactView: View {
    
    @State var name: String = ""
    @State var email: String = ""
    @State var isButtonPressed: Bool = false
    
    @EnvironmentObject var myContacts: Contacts
    
    var body: some View {
        
       
        VStack{
            
            HStack{
                Text("Name:")
                TextField("Enter name", text: $name)
            }
            .padding(.bottom, 50)
            
            HStack{
                Text("Email:")
                TextField("Enter email", text: $email)
            }
            .padding(.bottom, 50)
            
            
            Button("Submit") {
                
                let contactToAdd = Contact(name: name, email: email)
                
                //Add is a simple function - all it does is append an item to the    myContacts array using the .append method
                myContacts.add(contact: contactToAdd)
                isButtonPressed = true
            }

            .frame(width: 80, height: 30, alignment:.center)
            .background(Color.blue)
            .foregroundColor(.white)
            .clipShape(Capsule())
                
            NavigationLink(destination: ContentView().navigationBarHidden(true),
                    isActive: $isButtonPressed,
                    label: {
                       EmptyView()
                    }).hidden()
            
        }.padding()
            
        }
    
}

What I've tried我试过的

If I comment out the the .add method and don't update the environment object, then the navigation back to ContentView works as expected.如果我注释掉 .add 方法并且不更新环境对象,则返回 ContentView 的导航按预期工作。 So I know that specifically is the cause of the problem.所以我知道这特别是问题的原因。

I've tried adding a .onTapGesture modifier to the Button and invoking .add there.我已经尝试将 .onTapGesture 修饰符添加到 Button 并在那里调用 .add 。

I've tried adding a .onDisappear modifier to the entire view and invoking .add there.我试过在整个视图中添加一个 .onDisappear 修饰符并在那里调用 .add 。

-- Any help or clarity on resolving this would be much appreciated - 对解决此问题的任何帮助或澄清将不胜感激

Edit: Screen Recording - trying solution based on first comment:编辑:屏幕录制 - 根据第一条评论尝试解决方案:

What happens when I try the solution 当我尝试解决方案时会发生什么

Odd behaviour: The first attempt at adding a contact auto-routes back to AddContactView, producing the same error.奇怪的行为:第一次尝试添加联系人自动路由回 AddContactView,产生相同的错误。 But if I try it a second time then it routes correctly to ContactView.但是如果我第二次尝试它,它就会正确地路由到 ContactView。

Edit update.编辑更新。 This is the code I used to test my answer:这是我用来测试我的答案的代码:

import SwiftUI

@main
struct TestApp: App {
    @StateObject var myContacts = Contacts()
    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(myContacts)
        }
    }
}

struct Contact: Identifiable {
    var id = UUID()
    var name: String = ""
    var email: String = ""
}

class Contacts: ObservableObject {
    @Published var contacts: [Contact] = [Contact(name: "name1", email: "email1"), Contact(name: "name2", email: "email2")]
    
    func add(contact: Contact) {
        contacts.append(contact)
    }
}

struct AddContactView: View {
    @Environment(\.presentationMode) private var presentationMode
    
    @EnvironmentObject var myContacts: Contacts
    
    @State var name: String = ""
    @State var email: String = ""

    var body: some View {
        VStack{
            HStack{
                Text("Name:")
                TextField("Enter name", text: $name)
            }
            .padding(.bottom, 50)
            HStack{
                Text("Email:")
                TextField("Enter email", text: $email)
            }
            .padding(.bottom, 50)
            Button("Submit") {
                let contactToAdd = Contact(name: name, email: email)
                myContacts.add(contact: contactToAdd)
                presentationMode.wrappedValue.dismiss()
            }
            .frame(width: 80, height: 30, alignment:.center)
            .background(Color.blue)
            .foregroundColor(.white)
            .clipShape(Capsule())
        }.padding()
    }
}

struct ContentView: View {
    @EnvironmentObject var myContacts: Contacts
    @State var isAddButtonPressed: Bool = false
    
    var body: some View {
        NavigationView {
            List {
                ForEach(myContacts.contacts) { item in
                    NavigationLink(destination: AddContactView()) {
                        Text(item.name)
                    }
                }
            }
            .navigationBarTitle("Address Book")
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading){
                    Button(action: {
                        isAddButtonPressed.toggle()
                    }, label: {
                        NavigationLink(
                            destination: AddContactView(),
                            isActive: $isAddButtonPressed,
                            label: {
                            Image(systemName: "plus")
                        })
                    })
                }
                ToolbarItem(placement: .navigationBarTrailing){
                    EditButton()
                }
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM