使用SwiftUI转到新视图

Jak*_*ake 10 swift swiftui

我已经有了使用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)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Geo*_*e_E 48

这不是这里的最佳答案 - 而是如果您不想要导航栏的替代方法。有关使用&执行此操作的正常方法,请参阅下面的Jake 回答。希望这仍然有用,或者也为您指明了正确的方向。NavigationViewNavigationLink

如果您只是想NavigationLink使用 a Binding,您可以使用NavigationLinkisActive绑定参数相同的init 。

无论如何,回到答案......


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

.navigate(to: MainPageView(), when: $willMoveToNextScreen)
Run Code Online (Sandbox Code Playgroud)

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

@State private var willMoveToNextScreen = false

var body: some View {
    VStack {
        /* ... */
    }
    .navigate(to: MainPageView(), when: $willMoveToNextScreen)
}
Run Code Online (Sandbox Code Playgroud)

代码(记住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()
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 干得好。还有一件事,有机会改变导航动画吗?默认情况下它始终是从左到右。 (2认同)
  • 我得到“无法同时满足约束”。可能以下列表中至少有一个约束是您不希望每个“.navigate()”遇到的约束 (2认同)
  • @TiagoMendes 将 `.navigationViewStyle(.stack)` 添加到 `NavigationView` 可能会修复它 (2认同)
  • 对于低于 IOS 16 的版本来说这是一个很好的答案,但 isActive 在 IOS 16 中已被弃用 (2认同)

Jak*_*ake 10

关键是使用NavigationView和NavigationLink:

import SwiftUI

struct ContentView : View {
    var body: some View {
        NavigationView {
            VStack {
                Text("Hello World")
                NavigationLink(destination: DetailView()) {
                    Text("Do Something")
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 有没有办法用“Button”而不是丑陋的 NavigationLink 来做到这一点? (8认同)

Saj*_*obi 10

iOS 16、SwiftUI 4

导航栈

如果您打算支持 iOS 16 及更高版本,则可以利用 NavigationStack 提供的优势。

您可以将其视为可以将您的视图推入其中的堆栈。因此,通过应用程序引导用户将变得更加容易。

如果这是我们想要移至此处的详细视图:

struct DetailView: View {
   var body: some View {
     Text("You are at detail view")
  }
}
Run Code Online (Sandbox Code Playgroud)

第一种方法是使用NavigationLink之前的类似方法。我们可以转向新的观点。

struct ContentView: View {
var body: some View {
    NavigationStack {
        VStack {
            NavigationLink {
                DetailView()
            } label: {
                Text("Show Detail")
            }
        }
        .navigationTitle("Navigation")
    }
   }
}
Run Code Online (Sandbox Code Playgroud)

第二种方法将使用value内部NavigationLink. 您可以传递一个值,然后.navigationDestination根据值类型进行定义。一旦用户触发该链接,SwiftUI 就会知道哪个navigationDestination应该负责处理该链接。

struct ContentView: View {
@State var fruits: [String] = ["", "", "", ""]
var body: some View {
    NavigationStack {
        VStack(spacing: 20) {
            NavigationLink("Navigate: String Value", value: "New Page")
            
            NavigationLink("Navigate: Int Value", value: 1)
            
            ForEach(fruits, id:\.self) { fruit in
                NavigationLink(fruit, value: fruit)
            }
        }
        .navigationDestination(for: String.self) { value in
            Text("New screen")
            Text("Value is String -> \(value)")
        }
        .navigationDestination(for: Int.self) { value in
            Text("New screen")
            Text("Value is Integer -> \(value)")
        }
    }
}
}
Run Code Online (Sandbox Code Playgroud)

第三种方法 NavigationStack通过定义路径来显示其价值。我们可以定义一条路径并根据类型控制我们的导航。以编程方式导航将变得更加容易。我们可以添加视图或从路径列表中删除它们。当我们想通过将路径列表清空来导航回根视图时,它也会非常有用。

struct ContentView: View {

@State var path: [String] = []
@State var fruits: [String] = ["", "", "", ""]

var body: some View {
    NavigationStack(path: $path) {
        ZStack {
            Button("Random fruits") {
                let random = fruits.randomElement()!
                path.append(random)
            }
        }
        .navigationDestination(for: String.self) { value in
            VStack(spacing: 20) {
                Text("New screen")
                Text("Value is String -> \(value)")
                
                Button("Random fruits") {
                    let random = fruits.randomElement()!
                    path.append(random)
                }
                
                Button("Back to Root") {
                    path.removeAll()
                }
            }
        }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


小智 9

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

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

  • 嗯。“PresentationButton”从哪里来? (3认同)

Moh*_*ari 8

如果希望显示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)
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

或者如果您想根据可@State用于更改可见性的条件隐藏它。

  • 使用导航视图并隐藏内容的问题在于 1)您仍然处于推送/弹出模型中,如果您永远不打算返回(弹出),那么该视图就坐在那里吃掉内存和周期(取决于其结构和复杂性),并且永远不会被处置。也许这在宏伟计划中不是问题,但对我来说感觉有点油腻。 (2认同)

小智 7

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

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


Bra*_*ang 6

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

我认为如果你真的需要按下按钮,下面的方法是一种简单、正式和动态的尝试方法。根据Paul Hudson 的视频,从 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)
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)