Let's say you want to present SearchViewController modally over current controller, which is inside of UITabBarController.

func showSearch() {
    present(SearchVC(), animated: true, completion: nil)

Does what it should. But presented controller will overlap with UITabBar, so you can't switch between tabs at this point. To resolve this issue:

func showSearch() {
    // uncomment this one if your controller not wrapped in UINavigationController
    // definesPresentationContext = true
    let search = SearchVC()
    search.modalPresentationStyle = .currentContext
    present(search, animated: true, completion: nil)

search.modalPresentationStyle = .currentContext this line says to UIKit, that it needs to find the first UIViewController, that defines a context, in stack and show modal in this context. By default UINavigationController and UITabBarController have this property as true.

But now we lose ability to pop to root controller in stack by tapping on selected UITabItem. Here we getting help from UITabBarControllerDelegate:

func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
    guard tabBarController.selectedViewController == viewController else { return true }
    viewController.dismiss(animated: true, completion: nil)
    return true

Work like a charm!
But if you present modal from 2+ screen in navigation stack, you will get warnings in console:
Unbalanced calls to begin/end appearance transitions for <TBModal.MiddleVC: 0x7fad0d417b90>.

What's going on?
search.modalPresentationStyle = .currentContext remove presenter's view after modal controller presentation, and put it back right before dismiss. But in same time UINavigationController removing this view from stack in popToRootViewController call (or some equivalent used by UIKit). So you adding and removing view at same time.

Easy fix: search.modalPresentationStyle = .overCurrentContext
Here we say: "Show this modal over a current context, but don't remove presenter's view from hierarchy"

Tagged with: