Skip to content

Instantly share code, notes, and snippets.

@NeilsUltimateLab
Created May 18, 2019 12:15
Show Gist options
  • Save NeilsUltimateLab/f1897ba62eef5afce0fda391a37195f5 to your computer and use it in GitHub Desktop.
Save NeilsUltimateLab/f1897ba62eef5afce0fda391a37195f5 to your computer and use it in GitHub Desktop.
Make any view controller popover controller.
import UIKit
class PopoverController: UIViewController {
enum Source {
case barButtonItem(item: UIBarButtonItem)
case sourceView(view: UIView?)
}
private var contentViewController: UIViewController?
private var source: Source = .sourceView(view: nil)
private var permittedArrowDirection: UIPopoverArrowDirection = .any
private var contentSize: CGSize = .zero
convenience init(contentViewController: UIViewController, source: Source, permittedArrowDirection: UIPopoverArrowDirection = .any, preferredContentSize: CGSize) {
self.init(nibName: nil, bundle: nil)
self.contentViewController = contentViewController
self.source = source
self.permittedArrowDirection = permittedArrowDirection
self.contentSize = preferredContentSize
prepareForPopover()
}
fileprivate func addAsChild(_ contentViewController: UIViewController) {
contentViewController.willMove(toParent: self)
self.view.addSubview(contentViewController.view)
contentViewController.view.translatesAutoresizingMaskIntoConstraints = false
contentViewController.view.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
contentViewController.view.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
contentViewController.view.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
contentViewController.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
self.addChild(contentViewController)
contentViewController.didMove(toParent: self)
}
private func removeFromChild() {
contentViewController?.willMove(toParent: nil)
contentViewController?.view?.removeFromSuperview()
contentViewController?.removeFromParent()
contentViewController?.didMove(toParent: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
guard let contentViewController = self.contentViewController else {
fatalError("There must be a view controller to present in popover.")
}
addAsChild(contentViewController)
}
deinit {
self.removeFromChild()
}
private func prepareForPopover() {
self.preferredContentSize = self.contentSize
self.modalPresentationStyle = .popover
self.popoverPresentationController?.delegate = self
}
}
extension PopoverController: UIPopoverPresentationControllerDelegate {
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
func prepareForPopoverPresentation(_ popoverPresentationController: UIPopoverPresentationController) {
popoverPresentationController.permittedArrowDirections = self.permittedArrowDirection
switch source {
case .barButtonItem(let item):
popoverPresentationController.barButtonItem = item
case .sourceView(let view):
popoverPresentationController.sourceView = view
popoverPresentationController.sourceRect = view?.bounds ?? .zero
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment