SwiftUI - 如何关闭假的模态视图 - 从里面的第二个视图,用关闭按钮?

Posted

技术标签:

【中文标题】SwiftUI - 如何关闭假的模态视图 - 从里面的第二个视图,用关闭按钮?【英文标题】:SwiftUI - How to close a fake Modal View - from the second view inside it, with a close button? 【发布时间】:2020-08-09 20:46:50 【问题描述】:

我有一个棘手的设计。我试图有一个关闭按钮,从任何视图,在“假”模态视图内(假因为它是全屏的,多亏了我在网上找到的代码),它将关闭模态视图。 现在关闭按钮在模态视图中打开的第一个视图中工作,但我需要它在模态视图的下一个视图中也能工作,因为我在这个模态视图中有一个流程来创建一个项目。

这是我启动 ColorNewItemView 的视图,我的假模态视图。

struct RecapItemToAdd: View 

  @State var isPresented: Bool = false

    var body: some View 
      NavigationView 
        
        VStack 
            
            Button(action:  withAnimation  self.isPresented.toggle()) 
            Image(systemName: "pencil")
                .resizable()
                .renderingMode(.original)
                .frame(width: 13, height: 17)
                .foregroundColor(UIManager.hLightGrey)
            

        
        
        ZStack 
             VStack(alignment: .leading) 
                 ColorNewItemView(isPresenteded: self.$isPresented)

                 Spacer()
               


         
         .background(Color.white)
         .edgesIgnoringSafeArea(.all)
         .offset(x: 0, y: self.isPresented ? 0 : UIApplication.shared.keyWindow?.frame.height ?? 0)
    

   
 

注意:我知道“keyWindow”已被弃用,但我不知道如何更改它。

使用 ColorNewItemView 启动我的全屏模式视图。在此视图中,关闭按钮有效。

   struct ColorNewItemView: View 

   @State var selection: Int? = nil

   @Binding var isPresenteded: Bool

      var body: some View 
      NavigationStackView 
         VStack(alignment: .center) 

          Button(action: 
                  self.isPresenteded = false
              ) 
                  Image(systemName: "xmark.circle.fill")
                  .resizable()
                  .frame(width: 30, height: 30)
                  .foregroundColor(UIManager.hBlueLight)
              
    
    Text("First View")
            .font(UIManager.einaTitle)
            .foregroundColor(UIManager.hDarkBlue)
    
    
    Image("black-hoodie")
    .resizable()
    .renderingMode(.original)
    .frame(width: 245, height: 300)
    
    PushView(destination: Color2NewItemView(isPresenteded: self.$isPresenteded), tag: 1, selection: $selection) 
                  
                 Button(action: self.selection = 1) 
                 Text("Avanti")
                      .font(UIManager.einaButton)
                      .foregroundColor(.white)
                      .frame(width: 291, height: 43)

                      .background(UIManager.buttonGradient)
                      .cornerRadius(6)
                      .shadow(color: UIManager.hBlueShadow, radius: 7, x: 0.0, y: 6.0)
                 
              

        
    
  
 

现在我在模态视图中有下一个视图,关闭按钮开始停止工作。

    struct Color2NewItemView: View 

    @Binding var isPresenteded: Bool
    @State var selection: Int? = nil

    var body: some View 
      VStack(alignment: .center) 


                 Button(action: 
                       self.isPresenteded = false
                   ) 
                       Image(systemName: "xmark.circle.fill")
                       .resizable()
                       .frame(width: 30, height: 30)
                       .foregroundColor(UIManager.hBlueLight)
                   

        Text("Second View")
                .font(UIManager.einaTitle)
                .foregroundColor(UIManager.hDarkBlue)


        Image("black-hoodie")
            .resizable()
            .renderingMode(.original)
            .frame(width: 245, height: 300)


        PushView(destination: FabricNewItemView(isPresenteded: $isPresenteded), tag: 1, selection: $selection) 

                         Button(action: self.selection = 1) 
                         Text("Tessuto")
                              .font(UIManager.einaButton)
                              .foregroundColor(.white)
                              .frame(width: 291, height: 43)

                              .background(UIManager.buttonGradient)
                              .cornerRadius(6)
                              .shadow(color: UIManager.hBlueShadow, radius: 7, x: 0.0, y: 6.0)
                         
        

                        Spacer()
                        .frame(height: 18)


                    PopView
                        Text("Back")
                        .font(UIManager.einaBodySemibold)
                        .foregroundColor(UIManager.hGrey)
                    

        
    

附言。 我还必须使用一个名为 NavigationStack 的库,因为我在页面底部有一个自定义后退按钮,并且导航视图不允许我在不使用导航栏中的后退的情况下弹出。

【问题讨论】:

【参考方案1】:

绑定可能会在深层视图层次结构中丢失,因此在接收到的级别上使用它更合适。

这是使用EnvironmentKey 的可能方法(与presentationMode 工作的想法相同)

引入包含一些闭包的辅助环境键

struct DismissModalKey: EnvironmentKey 

    typealias Value = () -> ()
    static let defaultValue =  


extension EnvironmentValues 
    var dismissModal: DismissModalKey.Value 
        get 
            return self[DismissModalKey.self]
        
        set 
            self[DismissModalKey.self] = newValue
        
    

所以在您的顶部模态视图中,您可以注入层次回调以关闭

struct ColorNewItemView: View 

   @State var selection: Int? = nil
   @Binding var isPresented: Bool

   var body: some View 
      NavigationStackView 
          // ... other code
      
      .environment(\.dismissModal,  self.isPresented = false )   // << here !!
   

因此这个环境值现在可用于所有子视图,您可以将其用作

struct Color2NewItemView: View 
   @Environment(\.dismissModal) var dismissModal
   
   @State var selection: Int? = nil

   var body: some View 
      VStack(alignment: .center) 
          Button(action: 
              self.dismissModal()       // << here !!
          ) 
      
      // ... other code
   

【讨论】:

它真的不适合我.. 我只是复制并粘贴您的代码,我是否必须以某种方式对其进行自定义? 嗯...您是否使用 UIViewController/UIHostingView 桥接在层次结构中的 ColorNewItemView 和 Color2NewItemView 之间? 谢谢!它有效,我遇到了另一个愚蠢的小问题。我的按钮在导航栏的区域,所以我无法点击它,我将它设置为隐藏并工作!

以上是关于SwiftUI - 如何关闭假的模态视图 - 从里面的第二个视图,用关闭按钮?的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI:从模态框内转到新视图

如何检测模态视图在 SwiftUI 中全局可见

如何使用 SwiftUI 在模态视图中创建 NSManagedObject?

如何在 SwiftUI 中关闭 ResearchKit 模态视图?

如何在 SwiftUI 中制作具有透明背景的模态视图?

如何在 SwiftUI 中使模态不可关闭