首页 > 解决方案 > 从 NavigationView 中关闭 SwiftUI 中的父模式

问题描述

我知道如何从子视图中关闭模式,@Environment (\.presentationMode) var presentationMode / self.presentationMode.wrappedValue.dismiss()但这是一个不同的问题。

当您在模态窗口中呈现多页NavigationView并浏览了几个页面时,对 NavigationView 的引用presentationMode将更改为 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")
    }
  }
}

标签: iosswiftui

解决方案


这是基于使用自己明确创建的环境密钥的可能方法(实际上我觉得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")
    }
  }
}

推荐阅读