Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Custom size popover in iOS SwiftUI
// -- Usage
struct Content: View {
@State var open = false
@State var popoverSize = CGSize(width: 300, height: 300)
var body: some View {
WithPopover(
showPopover: $open,
popoverSize: popoverSize,
content: {
Button(action: { self.open.toggle() }) {
Text("Tap me")
}
},
popoverContent: {
VStack {
Button(action: { self.popoverSize = CGSize(width: 300, height: 600)}) {
Text("Increase size")
}
Button(action: { self.open = false}) {
Text("Close")
}
}
})
}
}
// -- Source
struct WithPopover<Content: View, PopoverContent: View>: View {
@Binding var showPopover: Bool
var popoverSize: CGSize? = nil
let content: () -> Content
let popoverContent: () -> PopoverContent
var body: some View {
content()
.background(
Wrapper(showPopover: $showPopover, popoverSize: popoverSize, popoverContent: popoverContent)
.frame(maxWidth: .infinity, maxHeight: .infinity)
)
}
struct Wrapper<PopoverContent: View> : UIViewControllerRepresentable {
@Binding var showPopover: Bool
let popoverSize: CGSize?
let popoverContent: () -> PopoverContent
func makeUIViewController(context: UIViewControllerRepresentableContext<Wrapper<PopoverContent>>) -> WrapperViewController<PopoverContent> {
return WrapperViewController(
popoverSize: popoverSize,
popoverContent: popoverContent) {
self.showPopover = false
}
}
func updateUIViewController(_ uiViewController: WrapperViewController<PopoverContent>,
context: UIViewControllerRepresentableContext<Wrapper<PopoverContent>>) {
uiViewController.updateSize(popoverSize)
if showPopover {
uiViewController.showPopover()
}
else {
uiViewController.hidePopover()
}
}
}
class WrapperViewController<PopoverContent: View>: UIViewController, UIPopoverPresentationControllerDelegate {
var popoverSize: CGSize?
let popoverContent: () -> PopoverContent
let onDismiss: () -> Void
var popoverVC: UIViewController?
required init?(coder: NSCoder) { fatalError("") }
init(popoverSize: CGSize?,
popoverContent: @escaping () -> PopoverContent,
onDismiss: @escaping() -> Void) {
self.popoverSize = popoverSize
self.popoverContent = popoverContent
self.onDismiss = onDismiss
super.init(nibName: nil, bundle: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
func showPopover() {
guard popoverVC == nil else { return }
let vc = UIHostingController(rootView: popoverContent())
if let size = popoverSize { vc.preferredContentSize = size }
vc.modalPresentationStyle = UIModalPresentationStyle.popover
if let popover = vc.popoverPresentationController {
popover.sourceView = view
popover.delegate = self
}
popoverVC = vc
self.present(vc, animated: true, completion: nil)
}
func hidePopover() {
guard let vc = popoverVC, !vc.isBeingDismissed else { return }
vc.dismiss(animated: true, completion: nil)
popoverVC = nil
}
func presentationControllerWillDismiss(_ presentationController: UIPresentationController) {
popoverVC = nil
self.onDismiss()
}
func updateSize(_ size: CGSize?) {
self.popoverSize = size
if let vc = popoverVC, let size = size {
vc.preferredContentSize = size
}
}
}
}
@alaaosman20

This comment has been minimized.

Copy link

@alaaosman20 alaaosman20 commented May 3, 2020

it's not working as popOver it's showing as sheet

@wassupdoc

This comment has been minimized.

Copy link

@wassupdoc wassupdoc commented Jun 2, 2020

if you add the following func you'll get the popover on iPhone as well

func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
 return .none // this is what forces popovers on iPhone 
}
@sorin360

This comment has been minimized.

Copy link

@sorin360 sorin360 commented Aug 14, 2020

@wassupdoc Where should that func to be added ?

@dmallass

This comment has been minimized.

Copy link

@dmallass dmallass commented Oct 23, 2020

@ccwasden If the popovercontent is getting modiifed while using it, it doesn't reflect in the view

@dmallass

This comment has been minimized.

Copy link

@dmallass dmallass commented Oct 23, 2020

Ignore my above comment. I figured that out :)

@csmac3144

This comment has been minimized.

Copy link

@csmac3144 csmac3144 commented Mar 12, 2021

Brilliant mate -- a real help to SwiftUI folks :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment