我知道如何使用从子视图中关闭模态,@Environment (\.presentationMode) var presentationMode / self.presentationMode.wrappedValue.dismiss()但这是一个不同的问题。
当您NavigationView在模态窗口中显示多页并浏览了几个页面时,presentationMode对 NavigationView的引用将更改为 NavigationView,因此使用self.presentationMode.wrappedValue.dismiss()简单地弹出最后一个 NavigationView 而不是解除包含的模态。
是否有可能 - 如果有的话 - 如何从 NavigationView 树中的页面关闭包含模式?
这是一个显示问题的简单示例。如果您使用 SwiftUI 创建一个 Xcode Single View 应用程序项目并用ContentView它替换默认代码,它应该无需进一步更改即可工作。
import SwiftUI
struct ContentView: View {
@State var showModal: Bool = false
var body: some View {
Button(action: {
self.showModal.toggle()
}) {
Text("Launch Modal")
}
.sheet(isPresented: self.$showModal, onDismiss: {
self.showModal = false
}) {
PageOneContent()
}
}
}
struct PageOneContent: View {
var body: some View {
NavigationView {
VStack {
Text("I am Page One")
}
.navigationBarTitle("Page One")
.navigationBarItems(
trailing: NavigationLink(destination: PageTwoContent()) {
Text("Next")
})
}
}
}
struct PageTwoContent: View {
@Environment (\.presentationMode) var presentationMode
var body: some View {
NavigationView {
VStack {
Text("This should dismiss the modal. But it just pops the NavigationView")
.padding()
Button(action: {
// How to dismiss parent modal here instead
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Finish")
}
.padding()
.foregroundColor(.white)
.background(Color.blue)
}
.navigationBarTitle("Page Two")
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是基于使用自己明确创建的环境密钥的可能方法(实际上我觉得presentationMode用于这个用例是不正确的......无论如何)。
提议的方法是通用的,适用于模态视图层次结构中的任何视图。已测试并适用于 Xcode 11.2 / iOS 13.2。
// define env key to store our modal mode values
struct ModalModeKey: EnvironmentKey {
static let defaultValue = Binding<Bool>.constant(false) // < required
}
// define modalMode value
extension EnvironmentValues {
var modalMode: Binding<Bool> {
get {
return self[ModalModeKey.self]
}
set {
self[ModalModeKey.self] = newValue
}
}
}
struct ParentModalTest: View {
@State var showModal: Bool = false
var body: some View {
Button(action: {
self.showModal.toggle()
}) {
Text("Launch Modal")
}
.sheet(isPresented: self.$showModal, onDismiss: {
}) {
PageOneContent()
.environment(\.modalMode, self.$showModal) // < bind modalMode
}
}
}
struct PageOneContent: View {
var body: some View {
NavigationView {
VStack {
Text("I am Page One")
}
.navigationBarTitle("Page One")
.navigationBarItems(
trailing: NavigationLink(destination: PageTwoContent()) {
Text("Next")
})
}
}
}
struct PageTwoContent: View {
@Environment (\.modalMode) var modalMode // << extract modalMode
var body: some View {
NavigationView {
VStack {
Text("This should dismiss the modal. But it just pops the NavigationView")
.padding()
Button(action: {
self.modalMode.wrappedValue = false // << close modal
}) {
Text("Finish")
}
.padding()
.foregroundColor(.white)
.background(Color.blue)
}
.navigationBarTitle("Page Two")
}
}
}
Run Code Online (Sandbox Code Playgroud)
另一种方法是简单地使用这种情况的通知,并重置模态的触发标志。对我来说这不是最漂亮的解决方案,但它是我最有可能在几个月后仍然理解的解决方案。
import SwiftUI
struct ContentView: View {
@State var showModalNav: Bool = false
var body: some View {
Text("Present Modal")
.padding()
.onTapGesture {
showModalNav.toggle()
}.sheet(isPresented: $showModalNav, content: {
ModalNavView()
}).onReceive(NotificationCenter.default.publisher(for: Notification.Name(rawValue: "PushedViewNotifciation"))) { _ in
showModalNav = false
}
}
}
struct ModalNavView: View {
var body: some View {
NavigationView {
NavigationLink(
destination: PushedView(),
label: {
Text("Show Another View")
}
)
}
}
}
struct PushedView: View {
var body: some View {
Text("Pushed View").onTapGesture {
NotificationCenter.default.post(Notification.init(name: Notification.Name(rawValue: "PushedViewNotifciation")))
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果您不想通过通知松散地耦合视图,您也可以使用绑定,如下所示:
struct ContentView: View {
@State var showModalNav: Bool = false
var body: some View {
Text("Present Modal")
.padding()
.onTapGesture {
showModalNav.toggle()
}.sheet(isPresented: $showModalNav, content: {
ModalNavView(parentShowModal: $showModalNav)
}).onReceive(NotificationCenter.default.publisher(for: Notification.Name(rawValue: "PushedViewNotifciation"))) { _ in
showModalNav = false
}
}
}
struct ModalNavView: View {
@Binding var parentShowModal: Bool
var body: some View {
NavigationView {
NavigationLink(
destination: PushedView(parentShowModal: $parentShowModal),
label: {
Text("Show Another View")
}
)
}
}
}
struct PushedView: View {
@Binding var parentShowModal: Bool
var body: some View {
Text("Pushed View").onTapGesture {
parentShowModal = false
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2427 次 |
| 最近记录: |