Skip to content

Instantly share code, notes, and snippets.

@yoni-g
Last active Jul 27, 2020
Embed
What would you like to do?
How to present a popup menu in iOS?
//
// MenuOption.swift
//
struct MenuOption {
var title: String = ""
var image: UIImage
var action: (()->())
init(title: String, image: UIImage, action: @escaping (()->())) {
self.title = title
self.image = image
self.action = action
}
}
//
// PopoverMenu.swift
//
import UIKit
class PopoverMenuController: UITableViewController {
static let MENU_CELL_HEIGHT = 45
var menuOptions: [MenuOption]?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.view.alpha = 0
self.popoverPresentationController?.containerView?.alpha = 0
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UIView.animate(withDuration: 0.2, delay: 0.0, options: .beginFromCurrentState, animations: {
self.view.alpha = 1
self.popoverPresentationController?.containerView?.alpha = 1
}, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return menuOptions!.count
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return CGFloat(PopoverMenuController.MENU_CELL_HEIGHT)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "popoverMenuCell", for: indexPath) as! PopoverMenuCell
cell.title.text = menuOptions![indexPath.row].title.localized
cell.img.image = menuOptions![indexPath.row].image
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
menuOptions![indexPath.row].action()
self.dismiss(animated: false, completion: nil)
}
}
//
// PopoverMenuCell.swift
//
import UIKit
class PopoverMenuCell: UITableViewCell {
@IBOutlet weak var title: UILabel!
@IBOutlet weak var img: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
class PopoverUtils {
static func showPopoverMenu(_ sourceViewController: UIViewController, source: UIView, presentationDelegate: UIPopoverPresentationControllerDelegate, menuOptions: [MenuOption]) {
let vc = UIStoryboard(name: "Popover", bundle: Bundle.main).instantiateViewController(withIdentifier: "popoverMenuController") as! PopoverMenuController
vc.menuOptions = menuOptions
vc.modalPresentationStyle = .popover
vc.preferredContentSize = CGSize(width: 175, height: PopoverMenuController.MENU_CELL_HEIGHT * menuOptions.count)
if let presentationController = vc.popoverPresentationController {
presentationController.delegate = presentationDelegate
presentationController.backgroundColor = UIColor(hex: 0xEAEAEA)
presentationController.permittedArrowDirections = UIScreen.main.bounds.height - (source.superview?.convert(source.frame.origin, to: nil).y)! < 150 ? .down : .up
presentationController.sourceView = source
presentationController.sourceRect = source.bounds
sourceViewController.present(vc, animated: true, completion: {
vc.view.superview?.layer.cornerRadius = 0
})
}
}
}
@yoni-g

This comment has been minimized.

Copy link
Owner Author

@yoni-g yoni-g commented Jul 23, 2020

You also need to create a Storyboard with the PopoverMenuController viewCtlr in it - name it "popoverMenuController".
You can also create it as a .xib file..

image

@yoni-g

This comment has been minimized.

Copy link
Owner Author

@yoni-g yoni-g commented Jul 26, 2020

Example of how to use:

let menuOptions = [
	MenuOption(title: "menu_item_edit_basket".localized,   image: #imageLiteral(resourceName: "ico-edit-basket"), action: { self.editBasket(basket) }),
	MenuOption(title: "menu_item_delete_basket".localized, image: #imageLiteral(resourceName: "ico-delete-basket"), action: { self.deleteSavedBasket(basket) })
]

        
PopoverUtils.showPopoverMenu(self, source: sender, presentationDelegate: self, menuOptions: menuOptions)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment