|
import UIKit |
|
|
|
class AndroContextMenuAppearance{ |
|
static var MAX_HEIGHT: CGFloat = 300; |
|
static var WIDTH: CGFloat = 200; |
|
} |
|
|
|
class AndroContextMenu{ |
|
let screenSize = UIScreen.main.bounds; |
|
var options = [AndroContextMenuItem](); |
|
let contextMenuController = AndroContextMenuController(); |
|
let viewController: UIViewController! |
|
var anchorPoint: CGPoint!; |
|
var height: CGFloat = AndroContextMenuAppearance.MAX_HEIGHT; |
|
var width: CGFloat = AndroContextMenuAppearance.WIDTH; |
|
var convertedRect: CGRect!; |
|
|
|
init(viewController: UIViewController, sourceView: UIView, parentView: UIView){ |
|
self.viewController = viewController; |
|
convertedRect = parentView.convert(sourceView.frame, to: viewController.view); |
|
populateAnchorPoint(convertedRect); |
|
assert(self.viewController != nil, "viewController property should be assigned on constructor, so menu will be presented on that viewController"); |
|
prepare(); |
|
} |
|
|
|
func populateAnchorPoint(_ rect: CGRect){ |
|
var x: CGFloat = rect.minX - width + 5; |
|
var y: CGFloat = rect.maxY - 5; |
|
|
|
//Setting x Coordinate |
|
if x < 0{ |
|
x = rect.maxX - 5; |
|
} |
|
if x + width > screenSize.width{ |
|
x = rect.midX - width/2; |
|
} |
|
|
|
|
|
//Setting y Coordinate |
|
if y + height > screenSize.height{ |
|
y = rect.minY - height + 5; |
|
} |
|
if y < 0{ |
|
y = rect.midY - height/2; |
|
} |
|
|
|
anchorPoint = CGPoint(x: x, y: y); |
|
|
|
} |
|
|
|
private func prepare(){ |
|
contextMenuController.menu = self; |
|
contextMenuController.modalPresentationStyle = .overCurrentContext; |
|
contextMenuController.modalTransitionStyle = .crossDissolve; |
|
} |
|
|
|
func show(){ |
|
height = CGFloat(options.count * 44); |
|
if height > AndroContextMenuAppearance.MAX_HEIGHT{ |
|
height = AndroContextMenuAppearance.MAX_HEIGHT; |
|
} |
|
populateAnchorPoint(convertedRect); |
|
viewController.present(contextMenuController, animated: true, completion: nil); |
|
} |
|
|
|
func addOption(_ option: AndroContextMenuItem){ |
|
options.append(option); |
|
} |
|
} |
|
|
|
extension UIViewController{ |
|
func showAndroContextMenu(with options: [AndroContextMenuItem], sourceView: UIView, parentView: UIView){ |
|
let menu = AndroContextMenu(viewController: self, sourceView: sourceView, parentView: parentView); |
|
for option in options{ |
|
menu.addOption(option); |
|
} |
|
menu.show(); |
|
} |
|
} |
|
|
|
class AndroContextMenuController: UIViewController { |
|
let tableView = UITableView(); |
|
let button = UIButton(); |
|
var menu: AndroContextMenu!; |
|
|
|
override func viewDidLoad() { |
|
super.viewDidLoad(); |
|
self.view.backgroundColor = UIColor.black.withAlphaComponent(0.3); |
|
button.frame = self.view.bounds; |
|
button.backgroundColor = UIColor.clear; |
|
button.addTarget(self, action: #selector(AndroContextMenuController.dismissThis), for: .touchUpInside); |
|
self.view.addSubview(button); |
|
assert(menu != nil, "menu should not be null"); |
|
tableView.delegate = self; |
|
tableView.dataSource = self; |
|
tableView.frame.origin = menu.anchorPoint; |
|
tableView.frame.size = CGSize(width: menu.width, height: menu.height); |
|
tableView.separatorStyle = .none; |
|
tableView.backgroundColor = UIColor.white; |
|
tableView.layer.cornerRadius = 5; |
|
tableView.clipsToBounds = true; |
|
tableView.isScrollEnabled = AndroContextMenuAppearance.MAX_HEIGHT == menu.height; |
|
self.view.addSubview(tableView); |
|
} |
|
|
|
override func didReceiveMemoryWarning() { |
|
super.didReceiveMemoryWarning(); |
|
} |
|
|
|
func dismissThis(){ |
|
self.dismiss(animated: true, completion: nil); |
|
} |
|
} |
|
|
|
extension AndroContextMenuController: UITableViewDelegate, UITableViewDataSource{ |
|
func numberOfSections(in tableView: UITableView) -> Int { |
|
return 1; |
|
} |
|
|
|
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { |
|
return menu.options.count; |
|
} |
|
|
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { |
|
let cell = UITableViewCell(); |
|
let menuItem = menu.options[indexPath.row]; |
|
cell.textLabel?.text = menuItem.title; |
|
cell.textLabel?.textColor = menuItem.titleColor; |
|
return cell; |
|
} |
|
|
|
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { |
|
let menuItem = menu.options[indexPath.row]; |
|
menuItem.action?(menuItem); |
|
self.dismissThis(); |
|
} |
|
|
|
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { |
|
return 44; |
|
} |
|
} |
|
|
|
class AndroContextMenuItem{ |
|
var title: String = ""; |
|
var action: ((AndroContextMenuItem)->())? = nil; |
|
var titleColor: UIColor = UIColor.black; |
|
|
|
init(title: String, action: ((AndroContextMenuItem)->())? = nil, titleColor: UIColor? = nil){ |
|
self.title = title; |
|
self.action = action; |
|
if titleColor != nil{ |
|
self.titleColor = titleColor!; |
|
} |
|
} |
|
} |