【问题标题】:Go to a new view using SwiftUI使用 SwiftUI 转到新视图
【发布时间】:2019-10-19 14:20:16
【问题描述】:

我有一个使用 SwiftUI 的按钮的基本视图,我试图在点击按钮时呈现一个新的屏幕/视图。我该怎么做呢?我是否想为此视图创建一个委托,告诉应用程序的 SceneDelegate 呈现一个新的视图控制器?

import SwiftUI

struct ContentView : View {
    var body: some View {
        VStack {
            Text("Hello World")
            Button(action: {
                //go to another view
            }) {
                Text("Do Something")
                    .font(.largeTitle)
                    .fontWeight(.ultraLight)
            }
        }
    }
}

【问题讨论】:

    标签: swift swiftui


    【解决方案1】:

    这并不是这里的最佳答案 - 如果您不想要导航栏,它是一种替代方法。请参阅下面的Jake's answer,了解使用NavigationViewNavigationLink 执行此操作的常规方法。希望这仍然有用或为您指明正确的方向。

    如果您只是想让NavigationLinkBinding 一起使用,您可以使用与isActive 绑定参数相同的NavigationLink init。

    不管怎样,回到答案上来……


    我为此做了一个视图修饰符。这也意味着没有导航栏。你可以这样称呼它:

    .navigate(to: MainPageView(), when: $willMoveToNextScreen)
    

    这可以附在任何东西上,所以我通常将它附在身体的末端,例如:

    @State private var willMoveToNextScreen = false
    
    var body: some View {
        VStack {
            /* ... */
        }
        .navigate(to: MainPageView(), when: $willMoveToNextScreen)
    }
    

    代码(记得import SwiftUI):

    extension View {
        /// Navigate to a new view.
        /// - Parameters:
        ///   - view: View to navigate to.
        ///   - binding: Only navigates when this condition is `true`.
        func navigate<NewView: View>(to view: NewView, when binding: Binding<Bool>) -> some View {
            NavigationView {
                ZStack {
                    self
                        .navigationBarTitle("")
                        .navigationBarHidden(true)
    
                    NavigationLink(
                        destination: view
                            .navigationBarTitle("")
                            .navigationBarHidden(true),
                        isActive: binding
                    ) {
                        EmptyView()
                    }
                }
            }
            .navigationViewStyle(.stack)
        }
    }
    

    【讨论】:

    • 简洁的方法,虽然它似乎打破了我已经应用的样式的现有视图。
    • 非常简洁、整洁。最好的
    • 干得好。还有一件事,有机会改变导航动画吗?默认情况下它总是从左到右。
    • 我得到Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want 和每个.navigate()
    • @TiagoMendes 将.navigationViewStyle(.stack) 添加到NavigationView 可能会解决它
    【解决方案2】:

    关键是使用 NavigationView 和 NavigationLink:

    import SwiftUI
    
    struct ContentView : View {
        var body: some View {
            NavigationView {
                VStack {
                    Text("Hello World")
                    NavigationLink(destination: DetailView()) {
                        Text("Do Something")
                    }
                }
            }
        }
    }
    

    【讨论】:

    • NB 目前这种方法不适用于 Apple Watch,因为在 watchOS 中“NavigationView”不可用。您只能按照 here 的说明使用 NavigationLink
    • 这确实有效,但它紧密耦合了这些视图,有没有更好的方法让一个视图不知道另一个?
    • 有没有办法用 Button 代替丑陋的 NavigationLink?
    【解决方案3】:

    这是在不使用 NavigationView 的情况下呈现视图的另一种方法。这就像 UIKit 的UIModalPresentationStyle.currentContext

    struct PresenterButtonView: View {
    var body: some View {
        PresentationButton(Text("Tap to present"),
                           destination: Text("Hello world"))
    }}
    

    【讨论】:

    • 嗯。 PresentationButton 来自哪里?
    【解决方案4】:

    如果不想想要显示 navigationView,您可以将其隐藏在目的地。

    struct ContentViewA : View {
        var body: some View {
            NavigationView {
                VStack {
                    Text("Hello World")
                    NavigationLink(destination: ContentViewB()) {
                        Text("Go To Next Step")
                    }
                }
            }
        }
    }
    
    
    
    struct ContentViewB : View {
            var body: some View {
                NavigationView {
                    VStack {
                        Text("Hello World B")
    
                    }.navigationBarTitle("")
                    .navigationBarHidden(true)
                }
            }
        }
    

    或者如果您想根据条件隐藏它,您可以使用@State 来更改可见性。

    【讨论】:

    • 注意:.navigationBarTitle("") 确实隐藏了文本,但尴尬地在空视图中留下了间距。因此,只需使用修饰符.navigationBarHidden(true),然后实现自定义后退按钮或替代导航即可。
    • 使用导航视图并隐藏内容的问题在于 1) 您仍处于推送/弹出模型中,如果您从不打算返回(弹出),那么该视图是坐在那里吃记忆和循环(取决于它的结构和复杂性),并且永远不会被处置。也许这在宏伟计划中不是问题,但如果我觉得有点油腻。
    【解决方案5】:

    现在我们可以使用 NavigationLink


    文件 A:

    struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack {
                Text("Hello World")
                NavigationLink(destination: secondView()) {
                    Text("Hit Me!")
                        .fontWeight(.semibold)
                        .font(.title)
                        .padding()
                        .foregroundColor(.white)
                        .background(LinearGradient(gradient: Gradient(colors: [Color(.white),Color(.blue)]), startPoint: .leading, endPoint: .trailing))
                        .cornerRadius(40)
            }
          }
        }
      }
    }
    

    文件 B:

    struct secondView: View {
    var body: some View {
        VStack {
        VStack(alignment: .leading) {
            Text("Turtle Rock")
                .font(.title)
            HStack(alignment: .top) {
                Text("Joshua Tree National Park")
                    .font(.subheadline)
                Spacer()
                Text("California")
                    .font(.subheadline)
            }
        }
        .padding()
            Spacer()
    
        }
      }
    }                                                                                                  
    

    【讨论】:

      【解决方案6】:

      我认为这是最简单明了的方法。 在 UI 工具之后使用 fullScreenCover

      Button(action: {
               //code
               }){
                 Text("Send")
               }.fullScreenCover(isPresented: self.$model.goToOtherView, content: {
                          OtherView()
                      })
      

      【讨论】:

      • 问题在于它没有为 fullScreenCover 设置背景颜色
      • 有趣,但我也看到这是 XCode 中的 iOS 14.0 唯一功能。
      【解决方案7】:

      OP 已在此处多次回答,但我只是想通过显示视图 A 以及视图 B 也将使用的数据来演示 SwiftUI 的酷方面,您可以通过创建 @State 来传递数据视图 A 并在视图 B 中使用 @Binding 声明声明相同的变量

      struct ViewA : View {
          @State var myItems: [Items]
          var body: some View {
              NavigationView {
                  VStack {
                      NavigationButton(destination: ViewB(items: $myItems)) {
                          Text("Go To ViewB")
                      }
                  }
              }
          }
      }
      
      struct ViewB : View {
          @Binding var myItems: [Items]
          var body: some View {
              NavigationView {
                  List{
                      ForEach(myItems.identified(by: \.self)) {
                          Text($0.itemName)
                      }
                  }.navigationBarTitle(Text("My Items"))
              }
          }
      }
      

      【讨论】:

        【解决方案8】:

        我认为 Jake 的回答是 NextView 的基本方式。

        如果您真的需要按下按钮,我认为下面的方式是一种简单、正式和动态的尝试方式。根据Paul Hudson's Video,从 10'00" 到 12'00"。

        (应该转到 12'00" 到 15'00",如果您想通过点击不同的按钮转到不同的视图。) (应该转到 15'00" 到 16'00",如果您想转到第二个视图并自动返回。)还有更多

        这是代码示例。

        import SwiftUI
        
        struct ContentView: View {
        
            @State var areYouGoingToSecondView: Bool // Step 2
        
            var body: some View {
                NavigationView{ // Step 1
        
                    VStack {
        
                        // Step 3
                        NavigationLink(destination: YourSecondView(), isActive: $areYouGoingToSecondView) { EmptyView() }
        
        
                        Text("Hello World")
        
                        Button(action: {
                            self.areYouGoingToSecondView = true // Step 4
        
                        }) {
                            Text("Do Something (Go To Second View)")
                            .font(.largeTitle)
                            .fontWeight(.ultraLight)
                        }
                    }
                }
            }
        }
        

        【讨论】:

          【解决方案9】:

          您不能再使用 NavigationButton。相反,您应该使用 NavigationLink。

          struct ContentView: View {
              var body: some View {
                  NavigationView {
                      NavigationLink(destination: DetailView()) {
                          Text("Push new screen")
                      }
                  }
              }
          }
          

          【讨论】:

            【解决方案10】:

            我们可以在 Navigation 中使用 Text 并使其像 Button http://g.recordit.co/CkIkjvikfu.gif

            struct HomeContent: View {
                var body: some View {
                    NavigationView{
                        VStack {
                            NavigationLink(
                            destination: LoginContentView()) {
                                
                                    
                                       
                                Text("Login")
                                    .font(.title)
                                    .foregroundColor(Color.white)
                                    .multilineTextAlignment(.center)
                                    .frame(width: 300.0, height: 50.0)
                                    .background(Color(UIColor.appLightBlue))
                               
                            }
                            
                        }
                    }
                }
            }
            

            【讨论】:

            • 我认为您错过了问题的重点。 1)登录不应该有后退按钮,2)登录表单下留下的任何东西都仍然存在,没有被删除,没有被处理,3)当你推送登录时会发生什么?您肯定会想要完全转到另一个屏幕,也许是应用程序的主屏幕,它应该成为新的根,而不是导航推送/弹出堆栈中间的某个地方。
            • 请再次阅读问题,问题是打开新屏幕,我的代码正在打开新屏幕。
            【解决方案11】:

            要以编程方式导航到链接而不显示视觉元素,请使用隐藏的NavigationLink 覆盖您的一个视图。

            在此示例中,UI 将在某些代码将 shouldNavigate 设置为 true 时进行导航:

            struct ProgramaticSample {
                @State var shouldNavigate = false
                
                var body: some View {
                    Text("Hello navigation")
                        .overlay(NavigationLink(
                            destination: DestinationScreen(),
                            isActive: $shouldNavigate) {}
                            .hidden())
                }
            }
            

            【讨论】:

              【解决方案12】:

              必须创建一个像 LandmarkDetail() 这样的 DetailView 并调用以 LandmarkDetail() 为目的地的 NavigationButton。现在详细视图已打开。

              用于将值传递给详细屏幕的方法。通过发送如下代码。

              struct LandmarkList: View {
                  var body: some View {
                      NavigationView {
                          List(landmarkData) { landmark in
                              NavigationButton(destination: LandmarkDetail()) {
                                  LandmarkRow(landmark: landmark)
                              }
                          }
                          .navigationBarTitle(Text("Landmarks"))
                      }
                  }
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2020-01-17
                • 1970-01-01
                • 2020-07-18
                • 1970-01-01
                • 2021-12-15
                • 1970-01-01
                • 1970-01-01
                • 2020-04-15
                相关资源
                最近更新 更多