Search code examples
macosswiftuipopovernspopover

Programaticly dismiss popover in SwifUI


I try to dismiss a popover with setting the variable, that shows it to false.

The sample code behaves quite strange. Is there a better way to dismiss the popover programaticly with the Cancel Button?

import SwiftUI

struct ContentView: View {
  let lines = ["line 1", "line 2","line 3"]
  var body: some View {
    List {
      ForEach(lines, id: \.self)
      { Line(text: $0)
      }
    }
  }
}

struct Line: View {
  @State var text: String
  @State var showSheet = false

  var body: some View {
    VStack
    { Text("\(text)")
      .onTapGesture {
        self.showSheet = true
      }
    }.popover( isPresented: self.$showSheet,
               arrowEdge: .trailing
             )
    { Pop(showSheet: self.$showSheet)
    }
  }
}

struct Pop: View {
  @Binding var showSheet: Bool

  var body: some View {
    VStack {   
      Text("Option 1")
      Text("Option 2")
      Button("Cancel")
      { self.showSheet = false
      }
    }
  }
}

Solution

  • It is not clear from question in which environment and what exactly strange happens, because as tested the provided code works well with Xcode 11.2/3+ and iOS13.2+.

    Anyway there is alternate approach to close popovers using \.presentationMode as below

    Update: Well, I've found that original question probably concerns about macOS, because provided on macOS popover is not closed with described scenario.

    Here is a variant of usage for both iOS/macOS platforms (tested & works with Xcode 11.3 / macOS 10.15)

    struct Pop: View {
        @Binding var showSheet: Bool
        //@Environment(\.presentationMode) var presentationMode
        
        var body: some View {
            VStack {
                Text("Option 1")
                Text("Option 2")
                Button("Cancel")
                {
                    #if os(OSX)
                    NSApp.sendAction(#selector(NSPopover.performClose(_:)), to: nil, from: nil)
                    #else
                    //self.presentationMode.wrappedValue.dismiss() // << behaves the same as below
                    self.showSheet = false
                    #endif
                }
            }
        }
    }