I am trying to create a slide up menu, completely defined in a custom class named OldMenu.
It would show every time a user tap a UIBarButtonItem, that is also defined in that class.
So the button, the menu, and the menu animation to show the menu are all defined in this custom class.
For now, I can just access the button from an other class but it doesn't seem to trigger the animation to show the menu.
Any one knows why this code isn't working?
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let oldMenu = OldMenu()
navigationItem.rightBarButtonItems = [oldMenu.MenuButton]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
class OldMenu: NSObject, UITableViewDelegate, UITableViewDataSource {
var tableView: UITableView {
let tableView = UITableView()
tableView.isScrollEnabled = true
tableView.delegate = self
tableView.dataSource = self
tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "Cell")
return tableView
}
var transparentView = UIView()
let height: CGFloat = 250
var MenuButton: UIBarButtonItem {
let btn = UIBarButtonItem()
btn.title = "Menu"
btn.target = self
btn.action = #selector(onClickMenu)
return btn
}
}
extension OldMenu {
@objc func onClickMenu(_ sender: Any) {
let window = UIApplication.shared.keyWindow
transparentView.backgroundColor = UIColor.black.withAlphaComponent(0.9)
transparentView.frame = window?.bounds ?? .zero
window?.addSubview(transparentView)
let screenSize = UIScreen.main.bounds.size
tableView.frame = CGRect(x: 0, y: screenSize.height, width: screenSize.width, height: height)
window?.addSubview(tableView)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(onClickTransparentView))
transparentView.addGestureRecognizer(tapGesture)
transparentView.alpha = 0
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: {
self.transparentView.alpha = 0.5
self.tableView.frame = CGRect(x: 0, y: screenSize.height - self.height, width: screenSize.width, height: self.height)
}, completion: nil)
}
@objc func onClickTransparentView() {
let screenSize = UIScreen.main.bounds.size
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: {
self.transparentView.alpha = 0
self.tableView.frame = CGRect(x: 0, y: screenSize.height, width: screenSize.width, height: self.height)
}, completion: nil)
}
}
extension OldMenu {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
}
class ViewController: UIViewController {
var oldMenu: OldMenu!
override func viewDidLoad() {
super.viewDidLoad()
oldMenu = OldMenu(controller: self)
navigationItem.rightBarButtonItem = oldMenu.MenuButton
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension ViewController: MenuDelegate {
func tableRowDidSelect(_ indexPath: IndexPath) {
}
}
OldMenu
class OldMenu: NSObject {
var presenter: UIViewController?
var menuController = MenuViewController()
var MenuButton: UIBarButtonItem!
init(controller: UIViewController?) {
super.init()
presenter = controller
MenuButton = UIBarButtonItem(title: "Menu", style: .plain, target: self, action: #selector(onClickMenu))
}
@objc func onClickMenu() {
menuController.modalPresentationStyle = .custom
menuController.transitioningDelegate = self
menuController.delegate = presenter as! MenuDelegate
presenter?.present(menuController, animated: true, completion: nil)
}
}
extension OldMenu: UIViewControllerTransitioningDelegate {
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
PresentationController(presentedViewController: presented, presenting: presenting)
}
}
MenuViewController
Configure your tableView in MenuViewController, and use delegates to communicate back to the main view
protocol MenuDelegate {
func tableRowDidSelect(_ indexPath: IndexPath)
}
// Configure your tableView in MenuViewController
// Use delegates to communicate back to main view
class MenuViewController: UIViewController {
var delegate: MenuDelegate?
override func viewDidLoad() {
view.backgroundColor = .gray
}
}
PresentationController
You can reuse PresentationController to present view controllers in half screen.
import Foundation
import UIKit
class PresentationController: UIPresentationController {
let blurEffectView: UIVisualEffectView!
var tapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer()
override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
let blurEffect = UIBlurEffect(style: .dark)
blurEffectView = UIVisualEffectView(effect: blurEffect)
super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissController))
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.blurEffectView.isUserInteractionEnabled = true
self.blurEffectView.addGestureRecognizer(tapGestureRecognizer)
}
override var frameOfPresentedViewInContainerView: CGRect {
// Set your presentation height
let presentHeight: CGFloat = 300
return CGRect(origin: CGPoint(x: 0, y: self.containerView!.frame.height - presentHeight),
size: CGSize(width: self.containerView!.frame.width, height: presentHeight))
}
override func presentationTransitionWillBegin() {
self.blurEffectView.alpha = 0
self.containerView?.addSubview(blurEffectView)
self.presentedViewController.transitionCoordinator?.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) in
self.blurEffectView.alpha = 0.5
}, completion: { (UIViewControllerTransitionCoordinatorContext) in })
}
override func dismissalTransitionWillBegin() {
self.presentedViewController.transitionCoordinator?.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) in
self.blurEffectView.alpha = 0
}, completion: { (UIViewControllerTransitionCoordinatorContext) in
self.blurEffectView.removeFromSuperview()
})
}
override func containerViewWillLayoutSubviews() {
super.containerViewWillLayoutSubviews()
// set your corner radius
presentedView!.roundCorners([.topLeft, .topRight], radius: 18)
}
override func containerViewDidLayoutSubviews() {
super.containerViewDidLayoutSubviews()
presentedView?.frame = frameOfPresentedViewInContainerView
blurEffectView.frame = containerView!.bounds
}
@objc func dismissController(){
self.presentedViewController.dismiss(animated: true, completion: nil)
}
}
extension UIView {
func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
layer.mask = mask
}
}