从NavigationView中取消SwiftUI中的父模态 [英] Dismiss a parent modal in SwiftUI from a NavigationView

查看:159
本文介绍了从NavigationView中取消SwiftUI中的父模态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道如何使用@Environment (\.presentationMode) var presentationMode / self.presentationMode.wrappedValue.dismiss()从子视图中删除模态,但这是一个不同的问题.

I am aware of how to dismiss a modal from a child view using @Environment (\.presentationMode) var presentationMode / self.presentationMode.wrappedValue.dismiss() but this is a different issue.

当您在模式窗口中显示多页NavigationView并浏览了几页时,对presentationMode的引用将更改为NavigationView,因此使用self.presentationMode.wrappedValue.dismiss()只是弹出最后一个NavigationView比消除包含的模态.

When you present a multi-page NavigationView in a modal window, and have navigated through a couple of pages, the reference to presentationMode changes to be the NavigationView, so using self.presentationMode.wrappedValue.dismiss() simply pops the last NavigationView rather than dismissing the containing modal.

是否可以-以及如何-从NavigationView树中的页面中消除包含的模态?

Is it possible - and if so how - to dismiss the containing modal from a page in a NavigationView tree?

这是一个显示问题的简单示例.如果您使用SwiftUI创建一个Xcode Single View应用项目,并用它替换默认的ContentView代码,则该代码无需任何进一步的更改即可工作.

Here's a simple example showing the problem. If you create an Xcode Single View app project using SwiftUI and replace the default ContentView code with this, it should work with no further changes.

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")
    }
  }
}

推荐答案

以下是基于用法自己明确创建的环境密钥的可行方法(实际上,我觉得在此用例中使用presentationMode是不正确的. . 反正).

Here is possible approach based on usage own explicitly created environment key (actually I have feeling that it is not correct to use presentationMode for this use-case.. anyway).

提议的方法是通用的,并且可以从模式视图层次结构的任何视图中使用.经过测试与Xcode 11.2/iOS 13.2兼容.

Proposed approach is generic and works from any view in modal view hierarchy. Tested & works with 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")
    }
  }
}

这篇关于从NavigationView中取消SwiftUI中的父模态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆