【问题标题】:NavigationView and NavigationLink on button click in SwiftUI?在 SwiftUI 中单击按钮时的 NavigationView 和 NavigationLink?
【发布时间】:2020-01-08 00:08:23
【问题描述】:

我正在尝试从登录视图推送到详细视图,但无法成功。即使导航栏未显示在登录视图中。如何在 SwiftUI 中按下按钮?如何在按钮点击时使用 NavigationLink?

var body: some View {
    
    NavigationView {
        VStack(alignment: .leading) {
            Text("Let's get you signed in.")
                .bold()
                .font(.system(size: 40))
                .multilineTextAlignment(.leading)
                .frame(width: 300, height: 100, alignment: .topLeading)
                .padding(Edge.Set.bottom, 50)
            
            Text("Email address:")
                .font(.headline)
            TextField("Email", text: $email)
                .frame(height:44)
                .accentColor(Color.white)
                .background(Color(UIColor.darkGray))
                .cornerRadius(4.0)
            
            Text("Password:")
                .font(.headline)
            
            SecureField("Password", text: $password)
                .frame(height:44)
                .accentColor(Color.white)
                .background(Color(UIColor.darkGray))
                .cornerRadius(4.0)
            
            Button(action: {
                print("login tapped")
            }) {
                HStack {
                    Spacer()
                    Text("Login").foregroundColor(Color.white).bold()
                    Spacer()
                }
            }
            .accentColor(Color.black)
            .padding()
            .background(Color(UIColor.darkGray))
            .cornerRadius(4.0)
            .padding(Edge.Set.vertical, 20)
        }
        .padding(.horizontal,30)
    }
    .navigationBarTitle(Text("Login"))
}

【问题讨论】:

    标签: ios swift swiftui


    【解决方案1】:

    要解决您的问题,您需要使用NavigationLink 绑定和管理标签,因此在您的视图中创建一个状态如下,只需添加上面的正文。

    @State var selection: Int? = nil
    

    然后更新您的按钮代码如下添加NavigationLink

    NavigationLink(destination: Text("Test"), tag: 1, selection: $selection) {
        Button(action: {
            print("login tapped")
            self.selection = 1
        }) {
            HStack {
                Spacer()
                Text("Login").foregroundColor(Color.white).bold()
                Spacer()
            }
        }
        .accentColor(Color.black)
        .padding()
        .background(Color(UIColor.darkGray))
        .cornerRadius(4.0)
        .padding(Edge.Set.vertical, 20)
    }
    

    Meaning is, when selection and NavigationLink tag value will match then navigation will be occurs.

    希望对你有帮助。

    【讨论】:

    • 我尝试使用它。但实际上如何在按钮点击时写下来。因为我遇到了错误。
    • 您实际上并不需要 tag+selection 变体。有一个更简单的 isActive 变体 - 请参阅 this answer
    • @pawello2222 isActive 当您希望通过单击按钮触发导航时,似乎很难开始工作。我发现这个答案中的方法非常适合这种用例。
    【解决方案2】:

    接受的答案使用NavigationLink(destination:tag:selection:),这是正确的。

    但是,对于只有一个 NavigationLink 的简单视图,您可以使用 更简单 变体:NavigationLink(destination:isActive:)


    用法#1

    NavigationLink 由标准Button 激活:

    struct ContentView: View {
        @State var isLinkActive = false
    
        var body: some View {
            NavigationView {
                VStack(alignment: .leading) {
                    ...
                    NavigationLink(destination: Text("OtherView"), isActive: $isLinkActive) {
                        Button(action: {
                            self.isLinkActive = true
                        }) {
                            Text("Login")
                        }
                    }
                }
                .navigationBarTitle(Text("Login"))
            }
        }
    }
    

    用法#2

    NavigationLink隐藏并由标准Button 激活:

    struct ContentView: View {
        @State var isLinkActive = false
    
        var body: some View {
            NavigationView {
                VStack(alignment: .leading) {
                    ...
                    Button(action: {
                        self.isLinkActive = true
                    }) {
                        Text("Login")
                    }
                }
                .navigationBarTitle(Text("Login"))
                .background(
                    NavigationLink(destination: Text("OtherView"), isActive: $isLinkActive) {
                        EmptyView()
                    }
                    .hidden()
                )
            }
        }
    }
    

    用法#3

    NavigationLink隐藏并以编程方式激活:

    struct ContentView: View {
        @State var isLinkActive = false
    
        var body: some View {
            NavigationView {
                VStack(alignment: .leading) {
                    ...
                }
                .navigationBarTitle(Text("Login"))
                .background(
                    NavigationLink(destination: Text("OtherView"), isActive: $isLinkActive) {
                        EmptyView()
                    }
                    .hidden()
                )
            }
            .onAppear {
                self.isLinkActive = true
            }
        }
    }
    

    这是一个GitHub repository,它带有不同的 SwiftUI 扩展,使导航更容易。

    【讨论】:

    • 一个隐藏的 NavigationLink 来控制程序化的 segues 是一个启示。谢谢!
    • 使用新的 iOS 菜单功能以编程方式转到 NavLink 时,用法 #2 有效。 @pawello2222 - 天才。
    • 哇,Apple 真的把 NavigationView 搞糊涂了。
    • 等等,NavigationLink(destination:isActive:) 不适合拥有超过 1 个 NavigationLinks 的视图吗?
    • @user482594 您可以在一个视图中轻松使用多个NavigationLink(destination:isActive:) - 由多个@State 变量控制。如果链接彼此独立,则此方法效果最佳。但是,NavigationLink(destination:tag:selection:) 可能更适合需要添加多个 related NavigationLinks 的情况 - 例如在列表中等。
    【解决方案3】:

    另一种方法:

    场景代理

    if let windowScene = scene as? UIWindowScene {
                let window = UIWindow(windowScene: windowScene)
                window.rootViewController = UIHostingController(rootView: BaseView().environmentObject(ViewRouter()))
                self.window = window
                window.makeKeyAndVisible()
            }
    

    基础视图

    import SwiftUI
    
    struct BaseView : View {
    
        @EnvironmentObject var viewRouter: ViewRouter
    
        var body: some View {
            VStack {
                if viewRouter.currentPage == "view1" {
                    FirstView()
                } else if viewRouter.currentPage == "view2" {
                    SecondView()
                        .transition(.scale)
                }
            }
        }
    }
    
    #if DEBUG
    struct MotherView_Previews : PreviewProvider {
        static var previews: some View {
            BaseView().environmentObject(ViewRouter())
        }
    }
    #endif
    

    ViewRouter

    import Foundation
    import Combine
    import SwiftUI
    
    class ViewRouter: ObservableObject {
    
        let objectWillChange = PassthroughSubject<ViewRouter,Never>()
    
        var currentPage: String = "view1" {
            didSet {
                withAnimation() {
                    objectWillChange.send(self)
                }
            }
        }
    }
    

    第一视图

    import SwiftUI
    
    struct FirstView : View {
    
        @EnvironmentObject var viewRouter: ViewRouter
    
        var body: some View {
            VStack {
                Button(action: {self.viewRouter.currentPage = "view2"}) {
                    NextButtonContent()
                }
            }
        }
    }
    
    #if DEBUG
    struct FirstView_Previews : PreviewProvider {
        static var previews: some View {
            FirstView().environmentObject(ViewRouter())
        }
    }
    #endif
    
    struct NextButtonContent : View {
        var body: some View {
            return Text("Next")
                .foregroundColor(.white)
                .frame(width: 200, height: 50)
                .background(Color.blue)
                .cornerRadius(15)
                .padding(.top, 50)
        }
    }
    

    第二视图

    import SwiftUI
    
    struct SecondView : View {
    
        @EnvironmentObject var viewRouter: ViewRouter
    
        var body: some View {
            VStack {
                Spacer(minLength: 50.0)
                Button(action: {self.viewRouter.currentPage = "view1"}) {
                    BackButtonContent()
                }
            }
        }
    }
    
    #if DEBUG
    struct SecondView_Previews : PreviewProvider {
        static var previews: some View {
            SecondView().environmentObject(ViewRouter())
        }
    }
    #endif
    
    struct BackButtonContent : View {
        var body: some View {
            return Text("Back")
                .foregroundColor(.white)
                .frame(width: 200, height: 50)
                .background(Color.blue)
                .cornerRadius(15)
                .padding(.top, 50)
        }
    }
    

    希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-25
      相关资源
      最近更新 更多