85

我在玩 SwiftUI 并希望能够在点击按钮时返回上一个视图,就像我们popViewControllerUINavigationController. 到目前为止有提供的方法吗?

我也尝试过NavigationDestinationLink这样做但没有成功。

struct AView: View {
    var body: some View {
        NavigationView {
            NavigationButton(destination: BView()) {
                Text("Go to B")
            }
        }
    }
}

struct BView: View {
    var body: some View {
        Button(action: {
            // Trying to go back to the previous view
            // previously: navigationController.popViewController(animated: true)
        }) {
            Text("Come back to A")
        }
    }
}
4

12 回答 12

81

如下修改您的 BView 结构。该按钮将像 UIKit 中的 popViewController 一样执行。

struct BView: View {
    @Environment(\.presentationMode) var mode: Binding<PresentationMode>
    var body: some View {
        Button(action: { self.mode.wrappedValue.dismiss() })
        { Text("Come back to A") }
    }
}
于 2019-08-02T21:58:34.990 回答
13

用于 @Environment(\.presentationMode) var presentationMode返回上一个视图。检查下面的代码以获得更多理解。

import SwiftUI

struct ContentView: View {


    var body: some View {

        NavigationView {
            ZStack {
                Color.gray.opacity(0.2)

                NavigationLink(destination: NextView(), label: {Text("Go to Next View").font(.largeTitle)})
            }.navigationBarTitle(Text("This is Navigation"), displayMode: .large)
                .edgesIgnoringSafeArea(.bottom)
        }
    }
}

struct NextView: View {
    @Environment(\.presentationMode) var presentationMode
    var body: some View {
        ZStack {
            Color.gray.opacity(0.2)
        }.navigationBarBackButtonHidden(true)
            .navigationBarItems(leading: Button(action: {
                self.presentationMode.wrappedValue.dismiss()
            }, label: { Image(systemName: "arrow.left") }))
            .navigationBarTitle("", displayMode: .inline)
    }
}


struct NameRow: View {
    var name: String
    var body: some View {
        HStack {
            Image(systemName: "circle.fill").foregroundColor(Color.green)
            Text(name)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
于 2020-02-01T11:34:06.037 回答
11

带有状态变量。试试看。

struct ContentViewRoot: View {
    @State var pushed: Bool = false
    var body: some View {
        NavigationView{
            VStack{
                NavigationLink(destination:ContentViewFirst(pushed: self.$pushed), isActive: self.$pushed) { EmptyView() }
                    .navigationBarTitle("Root")
                Button("push"){
                    self.pushed = true
                }
            }
        }
        .navigationViewStyle(StackNavigationViewStyle())
    }
}


struct ContentViewFirst: View {
    @Binding var pushed: Bool
    @State var secondPushed: Bool = false
    var body: some View {
        VStack{
            NavigationLink(destination: ContentViewSecond(pushed: self.$pushed, secondPushed: self.$secondPushed), isActive: self.$secondPushed) { EmptyView() }
                .navigationBarTitle("1st")
            Button("push"){
                self.secondPushed = true;
            }
        }
    }
}



struct ContentViewSecond: View {
    @Binding var pushed: Bool
    @Binding var secondPushed: Bool

    var body: some View {
        VStack{
            Spacer()
            Button("PopToRoot"){
                self.pushed = false
            } .navigationBarTitle("2st")

            Spacer()
            Button("Pop"){
                         self.secondPushed = false
                     } .navigationBarTitle("1st")
            Spacer()
        }
    }
}

在此处输入图像描述

于 2020-02-19T15:57:35.697 回答
8

如果您愿意,现在有一种方法可以以编程方式弹出 NavigationView。这是在测试版 5 中。

请注意,您不需要后退按钮。您可以以任何您喜欢的方式以编程方式触发 DetailView 中的 showSelf 属性。而且您不必在母版中显示“推送”文本。这可能是一个 EmptyView(),从而创建了一个不可见的 segue。

(新的 NavigationLink 功能接管了已弃用的 NavigationDestinationLink)

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
于 2019-07-30T01:22:19.933 回答
6

这似乎在 watchOS 上对我有用(尚未在 iOS 上尝试过):

@Environment(\.presentationMode) var presentationMode

然后当你需要弹出

self.presentationMode.wrappedValue.dismiss()
于 2019-09-02T10:57:21.623 回答
4

似乎大量的基本导航功能是超级错误的,这令人失望,可能值得暂时放弃以节省数小时的挫败感。对我来说,PresentationButton 是唯一有效的。TabbedView 选项卡不能正常工作,而且 NavigationButton 根本不适合我。如果 NavigationButton 适合您,听起来像 YMMV。

我希望他们在修复自动完成的同时修复它,这将使我们更好地了解我们可用的内容。与此同时,我不情愿地围绕它进行编码,并记录修复何时出现。不得不弄清楚我们是做错了什么还是它不起作用,这很糟糕,但这对你来说是测试版!

于 2019-06-09T15:41:36.150 回答
3

更新:此解决方案中的 NavigationDestinationLink API 自 iOS 13 Beta 5 起已弃用。现在建议将 NavigationLink 与 isActive 绑定一起使用。

我想出了一个使用 NavigationDestinationLink 在 NavigationView 中以编程方式推送/弹出视图的解决方案。

这是一个简单的例子:

import Combine
import SwiftUI

struct DetailView: View {
    var onDismiss: () -> Void

    var body: some View {
        Button(
            "Here are details. Tap to go back.",
            action: self.onDismiss
        )
    }
}

struct MainView: View {
    var link: NavigationDestinationLink<DetailView>
    var publisher: AnyPublisher<Void, Never>

    init() {
        let publisher = PassthroughSubject<Void, Never>()
        self.link = NavigationDestinationLink(
            DetailView(onDismiss: { publisher.send() }),
            isDetail: false
        )
        self.publisher = publisher.eraseToAnyPublisher()
    }

    var body: some View {
        VStack {
            Button("I am root. Tap for more details.", action: {
                self.link.presented?.value = true
            })
        }
            .onReceive(publisher, perform: { _ in
                self.link.presented?.value = false
            })
    }
}

struct RootView: View {
    var body: some View {
        NavigationView {
            MainView()
        }
    }
}

我在这里的一篇博文中写到了这个。

于 2019-07-11T04:37:41.080 回答
3

你也可以这样做.sheet

.navigationBarItems(trailing: Button(action: {
            self.presentingEditView.toggle()
        }) {
            Image(systemName: "square.and.pencil")
        }.sheet(isPresented: $presentingEditView) {
            EditItemView()
        })

在我的情况下,我从右侧导航栏项目中使用它,然后您必须创建EditItemView()要在该模式视图中显示的视图(在我的情况下)。

https://developer.apple.com/documentation/swiftui/view/sheet(ispresented:ondismiss:content:)

于 2020-11-12T14:59:11.980 回答
1

下面在 XCode11 GM 中为我工作

self.myPresentationMode.wrappedValue.dismiss()
于 2019-09-19T12:20:43.570 回答
1

编辑:这里的这个答案比我的要好,但两者都有效: SwiftUI dismiss modal

您真正想要(或应该想要)的是模态演示,这里有几个人提到过。如果你走这条路,你肯定需要能够以编程方式解除模式,Erica Sadun 在这里有一个很好的例子来说明如何做到这一点:https ://ericasadun.com/2019/06/16/swiftui-modal -介绍/

鉴于声明式编码和命令式编码之间的区别,解决方案可能并不明显(例如,将 bool 切换为 false 以消除模态),但如果您的模型状态是事实的来源,而不是UI 本身的状态。

这是我对 Erica 示例的快速介绍,使用传递给 TestModal 的绑定,以便它可以自行关闭,而不必成为 ContentView 本身的成员(为简单起见,Erica 就是这样)。

struct TestModal: View {
    @State var isPresented: Binding<Bool>

    var body: some View {
        Button(action: { self.isPresented.value = false }, label: { Text("Done") })
    }
}

struct ContentView : View {
    @State var modalPresented = false

    var body: some View {
        NavigationView {
            Text("Hello World")
            .navigationBarTitle(Text("View"))
            .navigationBarItems(trailing:
                Button(action: { self.modalPresented = true }) { Text("Show Modal") })
        }
        .presentation(self.modalPresented ? Modal(TestModal(isPresented: $modalPresented)) {
            self.modalPresented.toggle()
        } : nil)
    }
}
于 2019-06-26T13:59:34.303 回答
0

而不是 NavigationButton 使用 Navigation DestinationLink

但你应该导入组合

struct AView: View {
 var link: NavigationDestinationLink<BView>
var publisher: AnyPublisher<Void, Never>

init() {
    let publisher = PassthroughSubject<Void, Never>()
    self.link = NavigationDestinationLink(
        BView(onDismiss: { publisher.send() }),
        isDetail: false
    )
    self.publisher = publisher.eraseToAnyPublisher()
}

var body: some View {
    NavigationView {
        Button(action:{
        self.link.presented?.value = true


 }) {
            Text("Go to B")
        }.onReceive(publisher, perform: { _ in
            self.link.presented?.value = false
        })
    }
}
}

struct BView: View {
var onDismiss: () -> Void
var body: some View {
    Button(action: self.onDismiss) {
        Text("Come back to A")
    }
}
}
于 2019-07-24T08:34:22.803 回答
-1

在目标中传递要重定向的视图,在块中传递数据以传递到另一个视图。

NavigationLink(destination: "Pass the particuter View") {
    Text("Push")
}
于 2019-09-19T08:44:26.103 回答