【问题标题】:Abrupt transition between views within a Navigation View导航视图中视图之间的突然转换
【发布时间】:2021-09-05 19:57:53
【问题描述】:

我无法弄清楚如何从我的 SignInView() 顺利导航到我的 FirstView()。我的 FirstView() 在 Navigation Stack 中,但是视图之间的转换非常突然,并且没有通常使用 NavigationLink 获得的转换。我怎样才能让过渡工作?

非常感谢!

这里是相关代码...

struct ContentView: View {
    @EnvironmentObject var viewModel: AppViewModel
    
    var body: some View {
        VStack{
            NavigationView {
                if viewModel.signedIn {
                    FirstView()
                        .transition(.slide)
                } else {
                    //.onAppear method is used for keyboard management (See Misc Functions...)
                    SignInView()
                        .onAppear(perform: UIApplication.shared.addTapGestureRecognizer)
                        .navigationBarHidden(true)
                }
            }
            .onAppear {
                viewModel.listen()
            }
        }
        
    }
}



class AppViewModel: ObservableObject {
    private var db = Firestore.firestore()
    
    @Published var userInfo: User?
    @Published var signedIn: Bool = false
    
    var handle: AuthStateDidChangeListenerHandle?
    let authRef = Auth.auth()
    
    var authHandle : AuthStateDidChangeListenerHandle?
    var rootInfoCollection : CollectionReference!
    var userIdRef = ""

    
    
    func fetchUserData(){
        db.collection("Users").document("\(userIdRef)").getDocument { document, error in
            // Check for error
            if error == nil {
                // Check that this document exists
                if document != nil && document!.exists {
                    
                    self.userInfo = document.map { (documentSnapshot) -> User in
                        let data = documentSnapshot.data()
                        
                        let uid = data?["uid"] as? UUID ?? UUID()
                        let company = data?["company"] as? String ?? ""
                        let name = data?["name"] as? String ?? ""
                        let admin = data?["admin"] as? Bool ?? false
                        let photo = data?["photo"] as? String ?? ""
                        
                        return User(uid: uid, company: company, name: name, admin: admin, photo: photo)
                    }
                    
                    withAnimation {
                        self.signedIn = true
                    }
                    
                    
                }
            }
        }
        
    }
    
    func listen(){
        handle = authRef.addStateDidChangeListener({ auth, user in
            print(user?.email ?? "No User Found")
            
            if let user = auth.currentUser {
                self.userIdRef = user.uid
                self.rootInfoCollection = Firestore.firestore().collection("/Users/")
                
                DispatchQueue.main.async {
                    self.fetchUserData()
                }
                                
            } else {
                self.signedIn = false
            }
        })
        
    }
    
    func signIn(email: String, password: String){
        authRef.signIn(withEmail: email, password: password) { result, error in
            guard result != nil, error == nil else {
                return
            }
        }
    }
}




struct SignInView: View {
    
    @EnvironmentObject var viewModel: AppViewModel
    
    @State private var username : String = ""
    @State private var password : String = ""
    @State private var shouldShowLoginAlert: Bool = false
    @State var selectedImageArray : [Image] = []
    
    var disableLoginButton : Bool {
        return self.username.isEmpty || self.password.isEmpty
    }
    
    var body: some View {
        
        VStack{
            
            Image(uiImage: #imageLiteral(resourceName: "awText"))
                .resizable()
                .frame(width: 180, height: 100)
                .padding(.bottom, 50)
            
            TextField("Email", text: $username)
                .padding(.leading)
                .disableAutocorrection(true)
                .autocapitalization(.none)
            Rectangle().fill(Color.gray.opacity(0.25)).frame(height: 1, alignment: .center).padding(.bottom)
                .padding(.bottom)
                .onChange(of: self.username, perform: { value in
                    if value.count > 10 {
                        self.username = String(value.prefix(20)) //Max 10 Characters for Username.
                    }
                })
            
            SecureField("Password", text: $password)
                .padding(.leading)
                .disableAutocorrection(true)
                .autocapitalization(.none)
            Rectangle().fill(Color.gray.opacity(0.25)).frame(height: 1, alignment: .center)
                .onChange(of: self.username, perform: { value in
                    if value.count > 10 {
                        self.username = String(value.prefix(10)) //Max 10 Characters for Password.
                    }
                })
            
            
            //SignIn Button
            Button(action: {
                viewModel.signIn(email: username, password: password)
            }, label: {
                Text("Sign In")
                    .disabled(disableLoginButton)
                    .frame(width: 300, height: 50)
                    .background(Color.green)
                    .clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous))
                    .padding()
            })
}

【问题讨论】:

  • 您可以尝试使用FirstView().transition(.slide) 吗?你怎么看?
  • 不幸的是这没用..
  • oups 是的,你需要使用withAnimation,有人在下面发布了答案

标签: firebase google-cloud-firestore swiftui


【解决方案1】:

用您自己的动画替换默认的NavigationView 行为并不一定很简单。我将列出一种可能性,但另一种可能是使用真正的NavigationView 转换,但是一旦您使用FirstView,只需隐藏后退按钮。

要自己进行转换,您需要 一个NavigationView 的根元素、一个if 子句、一个transition(.slide)withAnimation。这是您的代码的简化版本,仅显示了这些元素:

class AppViewModel: ObservableObject {
    @Published var signedIn = false
}

struct FirstView : View {
    var body: some View {
        Text("Signed in")
    }
}

struct ContentView: View {
    @StateObject var viewModel = AppViewModel()
    
    var body: some View {
        
        NavigationView {
            VStack {
                if viewModel.signedIn {
                     FirstView()
                        .transition(.slide)
                } else {
                    Button("Sign me in") {
                        withAnimation {
                            viewModel.signedIn = true
                        }
                    }
                }
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .navigationBarHidden(true)
        }
    }
}

【讨论】:

  • 不幸的是,这也不起作用:(
  • @RapsIn4 如果您将我提供的代码复制并粘贴到 Xcode 中,它就可以工作。你能确定你的实施有什么不同吗?
  • 我更新了上面的代码以反映您的建议。除了使用 Firebase 之外,我看不出代码有任何差异。
  • 有很大的不同——看VStackNavigationView的顺序
  • 哈哈,就是这样!不敢相信我错过了。我真的很感谢你帮我解决这个问题。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多