firebase 导航链接移动到所需视图,然后恢复到上一视图

x33g5p2x  于 2022-11-17  发布在  其他
关注(0)|答案(3)|浏览(78)

我正在开发一个新的社交媒体应用程序,我的导航代码有问题。
一旦用户填写了注册表单,我希望他们被提示上传个人资料图片。我遇到的问题是,它显示了半秒钟的预期视图,然后直接回到注册视图。
我有一个处理UI的RegistrationView和一个负责服务器端通信的AuthViewModel。本质上,当用户完成输入信息并点击按钮时,AuthViewModel接管并将信息发送到firebase,然后触发一个Bool为真。
然后,我在RegistrationView上设置了一个NagivationLink,它侦听该bool,如果为真,则更改UI上的视图。

NavigationLink(destination: ProfilePhotoSelectorView(), isActive: $viewModel.didAuthenticateUser, label:{} )

XCode说它在iOS16中已经过时了,应该转移到他们开发的NavigationStack系统。但是,我看到的每一个指南都不能让它工作。我唯一能让它工作的时间是通过上面的代码,并返回这个UI故障。
下面是RegistrationView的完整代码

import SwiftUI

struct RegistrationView: View {
    @State private var email = ""
    @State private var username = ""
    @State private var fullName = ""
    @State private var password = ""
    @State private var isVerified = false

    @Environment(\.presentationMode) var presentationMode
    @EnvironmentObject var viewModel: AuthViewModel
    
    var body: some View {
        VStack{

                NavigationLink(destination: ProfilePhotoSelectorView(), isActive: $viewModel.didAuthenticateUser, label:{} )
            
            AuthHeaderView(title1: "Get Started.", title2: "Create Your Account.")
            VStack(spacing: 40) {
                CustomInputFields(imageName: "envelope", placeholderText: "Email", isSecureField: false, text: $email)
                
                CustomInputFields(imageName: "person", placeholderText: "Username", isSecureField: false, text: $username)
                
                CustomInputFields(imageName: "person", placeholderText: "Full Name", isSecureField: false, text: $fullName)
                
                CustomInputFields(imageName: "lock", placeholderText: "Password", isSecureField: true, text: $password)
            }
            .padding(32)
            
            
            Button {
                viewModel.register(withEmail: email, password: password, fullname: fullName, username: username, isVerified: isVerified)
            } label: {
                Text("Sign Up")
                    .font(.headline)
                    .foregroundColor(.white)
                    .frame(width: 340, height: 50)
                    .background(Color("AppGreen"))
                    .clipShape(Capsule())
                    .padding()
            }
            .shadow(color: .gray.opacity(0.5), radius: 10, x:0, y:0)
            
            Spacer()
            
            Button {
                presentationMode.wrappedValue.dismiss()
            } label: {
                HStack {
                    Text("Already Have And Account?")
                        .font(.caption)
                    
                    Text("Sign In")
                        .font(.footnote)
                        .fontWeight(.semibold)
                }
            }
            .padding(.bottom, 32)
            .foregroundColor(Color("AppGreen"))

        }
        .ignoresSafeArea()
        .preferredColorScheme(.dark)
    }
}

struct RegistrationView_Previews: PreviewProvider {
    static var previews: some View {
        RegistrationView()
    }
}

下面是AuthViewModel的完整代码

import SwiftUI
import Firebase

class AuthViewModel: ObservableObject {
    @Published var userSession: Firebase.User?
    @Published var didAuthenticateUser = false
    
    init() {
        self.userSession = Auth.auth().currentUser
        
        print("DEBUG: User session is \(String(describing: self.userSession?.uid))")
    }
    
    func login(withEmail email: String, password: String){
        Auth.auth().signIn(withEmail: email, password: password) { result, error in
            if let error = error {
                print("DEBUG: Failed to sign in with error\(error.localizedDescription)")
                return
            }
            
            guard let user = result?.user else { return }
            self.userSession = user
            print("Did log user in")
        }
    }
    
    func register(withEmail email: String, password: String, fullname: String, username: String, isVerified: Bool){
        Auth.auth().createUser(withEmail: email, password: password) { result, error in
            if let error = error {
                print("DEBUG: Failed to register with error\(error.localizedDescription)")
                return
            }
            
            guard let user = result?.user else { return }
            
            print("DEBUG: Registerd User Succesfully")
            
            let data = ["email": email, "username" :username.lowercased(), "fullname": fullname, "isVerified": isVerified, "uid": user.uid]
            
            Firestore.firestore().collection("users")
                .document(user.uid)
                .setData(data) { _ in
                    self.didAuthenticateUser = true
                }
        }
    }
    
    func signOut() {
        userSession = nil
        try? Auth.auth().signOut()
    }
}

下面是ProfilePhotoSelectorView的代码

import SwiftUI

struct ProfilePhotoSelectorView: View {
    var body: some View {
        VStack {
            AuthHeaderView(title1: "Account Creation:", title2: "Add A Profile Picture")
            
            Button {
                print("Pick Photo Here")
            } label: {
                VStack{
                    Image("PhotoIcon")
                        .resizable()
                        .renderingMode(.template)
                        .frame(width: 180, height: 180)
                        .scaledToFill()
                        .padding(.top, 44)
                        .foregroundColor(Color("AppGreen"))
                    
                    Text("Tap To Add Photo")
                        .font(.title3).bold()
                        .padding(.top, 10)
                        .foregroundColor(Color("AppGreen"))
                }
            }

            
            Spacer()
        }
        .ignoresSafeArea()
        .preferredColorScheme(.dark)
    }
}

struct ProfilePhotoSelectorView_Previews: PreviewProvider {
    static var previews: some View {
        ProfilePhotoSelectorView()
    }
}

尝试了新NavigationStack的所有变体,并尝试了一些其他按钮代码,看看我是否可以从那里触发它。没有Reso

xn1cxnb4

xn1cxnb41#

不推荐以这种方式使用NavigationLink,所以我并不奇怪它会导致错误的行为。这是由于您的RegistrationView没有放在NavigationView(已弃用)或NavigationStack中,因为这些视图提供了导航链接的大部分功能。
就像你说的,NavigationLink的这种用法已经过时了。在我看来,isActive属性一直有点模棱两可(据我所知,它并不是导航链接的“激活器”,而是一种读取链接是否活动的方式)。显示导航链接的新方式(使用.navigationDestination)要好得多。

使用布尔属性显示视图

实际上,你需要的是当一个布尔属性被切换为true时,显示ProfilePhotoSelectorView。这是SwiftUi中的常见范例,有很多方法可以实现这一点,比如.sheet(isPresented:content:).popover(isPresented:content:)。注意,这两个方法中的isPresented参数都是布尔属性。例如,使用.sheet

struct RegistrationView: View {
    // ...
    @EnvironmentObject var viewModel: AuthViewModel
    
    var body: some View {
        VStack {
            // ...
        }
        // Presents the photo selector view when `didAuthenticateUser` is true
        .sheet(isPresented: $viewModel.didAuthenticateUser) {
            ProfilePhotoSelectorView()
        }
    }
}

向导航树添加新视图

如果您坚持使用导航链接(也就是说,您 * 真的 * 希望ProfilePhotoSelectorView成为导航树中的一个节点),那么您必须学习使用新的NavigationStack并将视图追加到路径上。herehere是一个很好的起点)视图模型是最有可能控制堆栈的地方,尽管你最终可能想创建一个专用的视图模型。

struct ContentView: View {
    @StateObject var viewModel = AuthViewModel()
    
    var body: some View {
        NavigationStack(path: $viewModel.navigationPath) {
            RegistrationView()
                .environmentObject(viewModel)
                
                .navigationDestination(for: RegistrationScreen.self) { screen in
                    switch screen {
                    case .photoSelection:
                        ProfilePhotoSelectorView()
                    }
                }
        }
    }
}

class AuthViewModel: ObservableObject {
    // ...

    // A new enum that defines the various types of possible views in the navigation stack
    enum RegistrationScreen: Hashable {
        case photoSelection
    }

    // The navigation path
    @Published var navigationPath: [RegistrationScreen] = []

    // Example usages of the navigation path. These functions show how to programmatically control the navigation stack
    func showPhotoSelectionScreen() {
        self.navigationPath.append(.photoSelection)
    }

    func goToRootOfNavigation() {
        self.navigationPath = []
    }
}
pdsfdshx

pdsfdshx2#

如果我没理解错你的问题,你想使用NavigationStack,但它不适合你。
这里有许多遗漏的部分,但这里是我尝试使用NavigationStack来触发目的地,假定viewModel.didAuthenticateUser发生了变化。

struct ContentView: View {
    @StateObject var viewModel = AuthViewModel()
    
    var body: some View {
        NavigationStack(path: $viewModel.didAuthenticateUser) {  // <-- here
            RegistrationView()
                .environmentObject(viewModel)
        }
    }
}

struct RegistrationView: View {
    @State private var email = ""
    @State private var username = ""
    @State private var fullName = ""
    @State private var password = ""
    @State private var isVerified = false
    
    @Environment(\.presentationMode) var presentationMode
    @EnvironmentObject var viewModel: AuthViewModel
    
    var body: some View {
        VStack{
            AuthHeaderView(title1: "Get Started.", title2: "Create Your Account.")
            VStack(spacing: 40) {
                CustomInputFields(imageName: "envelope", placeholderText: "Email", isSecureField: false, text: $email)

                CustomInputFields(imageName: "person", placeholderText: "Username", isSecureField: false, text: $username)

                CustomInputFields(imageName: "person", placeholderText: "Full Name", isSecureField: false, text: $fullName)

                CustomInputFields(imageName: "lock", placeholderText: "Password", isSecureField: true, text: $password)
            }
            .padding(32)

            Button {
                viewModel.register(withEmail: email, password: password, fullname: fullName, username: username, isVerified: isVerified)
            } label: {
                Text("Sign Up")
                    .font(.headline)
                    .foregroundColor(.white)
                    .frame(width: 340, height: 50)
                    .background(Color("AppGreen"))
                    .clipShape(Capsule())
                    .padding()
            }
            .shadow(color: .gray.opacity(0.5), radius: 10, x:0, y:0)
            
            Spacer()
            
            Button {
                presentationMode.wrappedValue.dismiss()
            } label: {
                HStack {
                    Text("Already Have And Account?")
                        .font(.caption)
                    
                    Text("Sign In")
                        .font(.footnote)
                        .fontWeight(.semibold)
                }
            }
            .padding(.bottom, 32)
            .foregroundColor(Color("AppGreen"))
            
        }
        .navigationDestination(for: Bool.self) { _ in  // <-- here
            ProfilePhotoSelectorView()
        }
        .ignoresSafeArea()
        .preferredColorScheme(.dark)
    }
}

class AuthViewModel: ObservableObject {
    @Published var userSession: Firebase.User?
    @Published var didAuthenticateUser: [Bool] = [] // <-- here
    
    init() {
        self.userSession = Auth.auth().currentUser
        
        print("DEBUG: User session is \(String(describing: self.userSession?.uid))")
    }
    
    func login(withEmail email: String, password: String){
        Auth.auth().signIn(withEmail: email, password: password) { result, error in
            if let error = error {
                print("DEBUG: Failed to sign in with error\(error.localizedDescription)")
                return
            }

            guard let user = result?.user else { return }
            self.userSession = user
            print("Did log user in")
        }
    }
    
    func register(withEmail email: String, password: String, fullname: String, username: String, isVerified: Bool){

        Auth.auth().createUser(withEmail: email, password: password) { result, error in
            if let error = error {
                print("DEBUG: Failed to register with error\(error.localizedDescription)")
                return
            }

            guard let user = result?.user else { return }

            print("DEBUG: Registerd User Succesfully")

            let data = ["email": email, "username" :username.lowercased(), "fullname": fullname, "isVerified": isVerified, "uid": user.uid]

            Firestore.firestore().collection("users")
                .document(user.uid)
                .setData(data) { _ in
                    self.didAuthenticateUser = [true]  // <-- here
                }
        }
    }
    
    func signOut() {
        userSession = nil
        try? Auth.auth().signOut()
    }
}

struct ProfilePhotoSelectorView: View {
    var body: some View {
        VStack {
            AuthHeaderView(title1: "Account Creation:", title2: "Add A Profile Picture")

            Button {
                print("Pick Photo Here")
            } label: {
                VStack{
                    Image(systemName: "globe")
                        .resizable()
                        .renderingMode(.template)
                        .frame(width: 180, height: 180)
                        .scaledToFill()
                        .padding(.top, 44)
                        .foregroundColor(Color("AppGreen"))
                    
                    Text("Tap To Add Photo")
                        .font(.title3).bold()
                        .padding(.top, 10)
                        .foregroundColor(Color("AppGreen"))
                }
            }
            Spacer()
        }
        .ignoresSafeArea()
        .preferredColorScheme(.dark)
    }
}
holgip5t

holgip5t3#

除非将链接标记为isDetail(false)或使用.navigationStyle(.stack),否则只能有一个NavigationLink级别。
这是因为在横向模式下,它使用拆分视图,并且链接取代了右侧的大细节窗格。

相关问题