And*_*tto 16 ios swift swiftui
我找不到有关使用SwiftUI 以编程方式弹出或关闭 所显示视图的任何方式的任何参考。
在我看来,唯一的方法是对模式使用已经集成的幻灯片dow操作(以及是否/如何禁用此功能?),以及对导航堆栈使用后退按钮。
有人知道解决方案吗?您知道这是一个错误还是会一直保持这种状态?
Pra*_*wad 72
SwiftUI Xcode 测试版 5
首先,声明@Environment,它有一个dismiss 方法,你可以在任何地方使用它来关闭视图。
import SwiftUI
struct GameView: View {
@Environment(\.presentationMode) var presentation
var body: some View {
Button("Done") {
self.presentation.wrappedValue.dismiss()
}
}
}
Run Code Online (Sandbox Code Playgroud)
Chu*_*k H 14
本示例使用Beta 5版本说明中记录的新环境var,该环境使用value属性。在更高的Beta中对其进行了更改,以使用wrappedValue属性。该示例现在是GM版本的最新示例。此完全相同的概念可消除由.sheet修饰符显示的模态视图。
import SwiftUI
struct DetailView: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var body: some View {
Button(
"Here is Detail View. Tap to go back.",
action: { self.presentationMode.wrappedValue.dismiss() }
)
}
}
struct RootView: View {
var body: some View {
VStack {
NavigationLink(destination: DetailView())
{ Text("I am Root. Tap for Detail View.") }
}
}
}
struct ContentView: View {
var body: some View {
NavigationView {
RootView()
}
}
}
Run Code Online (Sandbox Code Playgroud)
我最近创建了一个名为swiftui-navigation-stack( https://github.com/biobeats/swiftui-navigation-stack ) 的开源项目,其中包含NavigationStackViewSwiftUI 的替代导航堆栈。它提供了 repo 的自述文件中描述的几个功能。例如,您可以轻松地以编程方式推送和弹出视图。我将通过一个简单的示例向您展示如何做到这一点:
首先,将您的层次结构嵌入到一个NavigationStackVew:
struct RootView: View {
var body: some View {
NavigationStackView {
View1()
}
}
}
Run Code Online (Sandbox Code Playgroud)
NavigationStackView使您的层次结构可以访问一个名为 的有用环境对象NavigationStack。例如,您可以使用它来以编程方式弹出视图,如上述问题中所述:
struct View1: View {
var body: some View {
ZStack {
Color.yellow.edgesIgnoringSafeArea(.all)
VStack {
Text("VIEW 1")
Spacer()
PushView(destination: View2()) {
Text("PUSH TO VIEW 2")
}
}
}
}
}
struct View2: View {
@EnvironmentObject var navStack: NavigationStack
var body: some View {
ZStack {
Color.green.edgesIgnoringSafeArea(.all)
VStack {
Text("VIEW 2")
Spacer()
Button(action: {
self.navStack.pop()
}, label: {
Text("PROGRAMMATICALLY POP TO VIEW 1")
})
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,我使用PushView来通过点击来触发推送导航。然后,在View2我使用环境对象以编程方式返回。
这是完整的示例:
import SwiftUI
import NavigationStack
struct RootView: View {
var body: some View {
NavigationStackView {
View1()
}
}
}
struct View1: View {
var body: some View {
ZStack {
Color.yellow.edgesIgnoringSafeArea(.all)
VStack {
Text("VIEW 1")
Spacer()
PushView(destination: View2()) {
Text("PUSH TO VIEW 2")
}
}
}
}
}
struct View2: View {
@EnvironmentObject var navStack: NavigationStack
var body: some View {
ZStack {
Color.green.edgesIgnoringSafeArea(.all)
VStack {
Text("VIEW 2")
Spacer()
Button(action: {
self.navStack.pop()
}, label: {
Text("PROGRAMMATICALLY POP TO VIEW 1")
})
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
RootView()
}
}
Run Code Online (Sandbox Code Playgroud)
结果是:
从 iOS 15 开始,我们可以使用一个新的@Environment(\.dismiss):
struct SheetView: View {
@Environment(\.dismiss) var dismiss
var body: some View {
NavigationView {
Text("Sheet")
.toolbar {
Button("Done") {
dismiss()
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
(不再需要使用presentationMode.wrappedValue.dismiss().)
有用的链接:
或者,如果您不想通过按钮以编程方式执行此操作,则可以在需要弹出时从视图模型中发出。订阅一个@Published,它会在保存完成时更改值。
struct ContentView: View {
@ObservedObject var viewModel: ContentViewModel
@Environment(\.presentationMode) var presentationMode
init(viewModel: ContentViewModel) {
self.viewModel = viewModel
}
var body: some View {
Form {
TextField("Name", text: $viewModel.name)
.textContentType(.name)
}
.onAppear {
self.viewModel.cancellable = self.viewModel
.$saved
.sink(receiveValue: { saved in
guard saved else { return }
self.presentationMode.wrappedValue.dismiss()
}
)
}
}
}
class ContentViewModel: ObservableObject {
@Published var saved = false // This can store any value.
@Published var name = ""
var cancellable: AnyCancellable? // You can use a cancellable set if you have multiple observers.
func onSave() {
// Do the save.
// Emit the new value.
saved = true
}
}
Run Code Online (Sandbox Code Playgroud)
请检查以下代码,非常简单。
第一视角
struct StartUpVC: View {
@State var selection: Int? = nil
var body: some View {
NavigationView{
NavigationLink(destination: LoginView().hiddenNavigationBarStyle(), tag: 1, selection: $selection) {
Button(action: {
print("Signup tapped")
self.selection = 1
}) {
HStack {
Spacer()
Text("Sign up")
Spacer()
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
第二视角
struct LoginView: View {
@Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView{
Button(action: {
print("Login tapped")
self.presentationMode.wrappedValue.dismiss()
}) {
HStack {
Image("Back")
.resizable()
.frame(width: 20, height: 20)
.padding(.leading, 20)
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以根据需要以编程方式弹出NavigationView。这是beta5。请注意,您不需要后退按钮。您可以通过任何方式以编程方式在DetailView中触发showSelf属性。而且您不必在母版中显示“推送”文本。那可能是EmptyView(),从而创建了一个看不见的序列。
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
MasterView()
}
}
}
struct MasterView: View {
@State var showDetail = false
var body: some View {
VStack {
NavigationLink(destination: DetailView(showSelf: $showDetail), isActive: $showDetail) {
Text("Push")
}
}
}
}
struct DetailView: View {
@Binding var showSelf: Bool
var body: some View {
Button(action: {
self.showSelf = false
}) {
Text("Pop")
}
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
Run Code Online (Sandbox Code Playgroud)