Search code examples
iosswiftuinavigationcontrolleruikituibarbuttonitem

UIBarButtonItems in UINavigationBar are unclickable


It seems my UIBarButtonItems are not responding at all to clicks.

I have a pan gesture recognizer attached to a TableViewController, however I have established this is not blocking it after enabling panGestureRecognizer.cancelsTouchesInView to false.

Right now the navigation controller is embedded in a ContainerViewController I created for managing a slide out view controller, included below:

import UIKit

class InstructorSlideOutContainerViewController: SlideOutContainerViewController {

var isFromLogin:Bool?

override func viewDidLoad() {
    super.viewDidLoad()
    setLeftViewController(identifier: "InstructorSettingsTableViewController")
    setCenterViewController(identifier: "InstructorClassesTableViewController")
    (centerViewController as! InstructorClassesTableViewController).delegate = self
    (centerViewController as! InstructorClassesTableViewController).touchDelegate = self
    (centerViewController as! InstructorClassesTableViewController).isFromLogin = isFromLogin

    centerNavigationController = UINavigationController(rootViewController: centerViewController!)
    view.addSubview(centerNavigationController.view)
    addChildViewController(centerNavigationController)

    centerNavigationController.didMove(toParentViewController: self)

    let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:)))
    centerNavigationController.view.addGestureRecognizer(panGestureRecognizer)
}

class func getEntrySegueFromFBLogin() -> String {
    return "FBLoginToInstructorContainerSegue"
}

class func getEntrySegueFromLogin() -> String {
    return "LoginToInstructorContainerSegue"
}

class func getEntrySegueFromSignUp() -> String {
   return "LoginToInstructorContainerSegue"
}
}

Which is a subclass of the generalized ContainerViewController:

enum SlideOutState {
    case LeftPanelClosed
    case LeftPanelExpanded
}

import UIKit

protocol SlideOutContainerViewControllerDelegate {
    func toggleLeftPanel()
}

protocol InitializeViewControllers {
    func setLeftViewController(identifier: String)
    func setCenterViewController(identifier: String)
}

class SlideOutContainerViewController: UIViewController {

    var centerNavigationController: UINavigationController!
    var centerViewController: UIViewController?
    var currentState: SlideOutState = .LeftPanelClosed
    var leftViewController: UIViewController?
    var centerViewControllerIdentifer = ""
    let centerPanelExpandedOffset: CGFloat = 60
    var mainStoryboard:UIStoryboard?
    override func viewDidLoad() {
        super.viewDidLoad()
        mainStoryboard = UIStoryboard(name: "Main", bundle: Bundle.main)
    }

}

extension SlideOutContainerViewController: InitializeViewControllers {

    func setLeftViewController(identifier: String) {
        leftViewController = mainStoryboard?.instantiateViewController(withIdentifier: identifier)
    }

    func setCenterViewController(identifier: String) {
       centerViewController = mainStoryboard?.instantiateViewController(withIdentifier: identifier)
    }
}

extension SlideOutContainerViewController: SlideOutContainerViewControllerDelegate {
    func toggleLeftPanel(){
        let notAlreadyExpanded = (currentState != .LeftPanelExpanded)
        if notAlreadyExpanded {
            addChildSidePanelController(sidePanelController: leftViewController!)
        }
        animateLeftPanel(shouldExpand: notAlreadyExpanded)
    }

    func addChildSidePanelController(sidePanelController: UIViewController) {
        view.insertSubview(sidePanelController.view, at: 0)
        addChildViewController(sidePanelController)
        sidePanelController.didMove(toParentViewController: self)
    }

    func animateLeftPanel(shouldExpand: Bool){
        if shouldExpand {
            currentState = .LeftPanelExpanded
            animateCenterPanelXPosition(targetPosition: centerNavigationController.view.frame.width - centerPanelExpandedOffset)
        } else {
            animateCenterPanelXPosition(targetPosition: 0) {finished in
                self.currentState = .LeftPanelClosed
                self.leftViewController?.view.removeFromSuperview()
            }
        }
    }

    func animateCenterPanelXPosition(targetPosition: CGFloat, completion: ((Bool) -> Void)! = nil) {
        UIView.animate(withDuration: 0.5, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: {
            self.centerNavigationController.view.frame.origin.x = targetPosition
        }, completion: completion)
    }

    func showShadowForCenterViewController(shouldShowShadow: Bool) {
        if shouldShowShadow {
            centerNavigationController.view.layer.shadowOpacity = 0.8
        } else {
            centerNavigationController.view.layer.shadowOpacity = 0.0
        }
    }
}

// MARK: Gesture Recognizer

extension SlideOutContainerViewController {
    func handlePanGesture(_ recognizer: UIPanGestureRecognizer) -> Void {
        let gestureIsDraggingFromLeftToRight = recognizer.velocity(in: view).x > 0

        switch recognizer.state {
        case .began:
            if currentState == .LeftPanelClosed {
                if gestureIsDraggingFromLeftToRight {
                    addChildSidePanelController(sidePanelController: leftViewController!)
                }
                showShadowForCenterViewController(shouldShowShadow: true)
            }
        case .changed:
            if gestureIsDraggingFromLeftToRight || currentState == .LeftPanelExpanded {
                recognizer.view!.center.x = recognizer.view!.center.x + recognizer.translation(in: view).x
                recognizer.setTranslation(CGPoint.zero, in: view)
            }
        case .ended:
            if leftViewController != nil {
                let hasMovedMoreThanHalfway = recognizer.view!.center.x > view.bounds.size.width
                animateLeftPanel(shouldExpand: hasMovedMoreThanHalfway)
            }
        default:
            break
        }
    }
}

Here's a screenshot of the storyboard.

picture So basically once the Containerviewcontroller loads, I cannot use any of the buttons in the navbar. Touches in the TableViewController still are registered, it seems it's just the UIBarButtonItems inside the UINavigationBar.

I double checked that all the outlets are connected, and right now am struggling to look for other solutions...

Thank you in advance!!

EDIT: I can get the buttons to work if I remove the embedded storyboard UINavigationController, however I need it there so that when segue'd to from another UINavigationController the <Back arrow doesn't show at the top of the NavigationController.


Solution

  • The solution was to segue to the viewcontroller with a modal segue, because the containerviewcontroller was competing with the navigationcontroller and needed to declare it's own instead of simply being pushed onto the navigation stack.