Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

add child UIViewConroller to UITabBarController

the structure of my app is following:

UITabBarController -> UINavigationController -> [UIViewController1, UIViewController2, UIViewController3]

What I need to achieve is showing and hiding a child UIViewController just above the tabBar in a small frame, so it is visible over all the controllers in the navigation stack. So when user navigates back and forth the stack, if that child is added it has to be visible over all controllers.

I have tried adding the child to the UITabBarController and it is working fine, the problem I get is that a shadow tabbar item is added to the tabbar, which I do not want.

I have tried adding the child to the navigation controller but that adds other problems when navigating back in the stack, it dismisses the child instead of self and loads the same controller.

Does anyone have a suggestion on how to keep this child controller throughout the whole navigation process.

I have searched for any suggestions here, but none was like my case, so not helpful.

Thank you

like image 702
stan Avatar asked Nov 16 '18 12:11

stan


2 Answers

I assume you added container view programmatically into you tabbar controller, then you added child view controller into that container view. Am I right?

If this is the case, tabbar controller added the child controller into its viewControllers array.

You can solve this by calling viewControllers?.removeLast() right after you've added your child.

This code worked for me:

override func viewDidLoad() {
    super.viewDidLoad()

    let containerView = UIView()
    view.addSubview(containerView)

    containerView.translatesAutoresizingMaskIntoConstraints = false
    containerView.bottomAnchor.constraint(equalTo: tabBar.topAnchor).isActive = true
    containerView.leftAnchor.constraint(equalTo: tabBar.leftAnchor, constant: 40).isActive = true
    containerView.rightAnchor.constraint(equalTo: tabBar.rightAnchor, constant: -40).isActive = true
    containerView.heightAnchor.constraint(equalToConstant: 150).isActive = true

    if let childVC = self.storyboard?.instantiateViewController(withIdentifier: "ChildViewController") {
        addChild(childVC)
        containerView.addSubview(childVC.view)
        childVC.didMove(toParent: self)

        childVC.view.translatesAutoresizingMaskIntoConstraints = false
        childVC.view.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
        childVC.view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true
        childVC.view.rightAnchor.constraint(equalTo: containerView.rightAnchor).isActive = true
        childVC.view.leftAnchor.constraint(equalTo: containerView.leftAnchor).isActive = true

        if let childIndex = viewControllers?.firstIndex(of: childVC) {
            viewControllers?.remove(at: childIndex)
        }
    }
}

Here, instead of just calling removeLast() I've checked if the childVC was actually in that array. Just to be on the safer side.

like image 71
Yevgeniy Leychenko Avatar answered Oct 11 '22 14:10

Yevgeniy Leychenko


The Problem:

Adding child view controller to UITablViewConltroller adds a new tab to the tab bar. and this appears clearly in iOS 13.4

The Solution

The solution is overriding viewControllers and return the original controllers only.

/// Neglect child insertion to `viewControllers`

var _viewControllers: [UIViewController]?

override var viewControllers: [UIViewController]? {
    get {
        return _viewControllers
    }
    set {
        _viewControllers = newValue
    }
}

Further more

To change tab bar item badge

//This would not work any more
//viewControllers?.last?.tabBarItem.badgeValue = badgeValue

//Use this way instead
tabBar.items?.last?.badgeValue = badgeValue
like image 1
Husam Avatar answered Oct 11 '22 14:10

Husam