Reputation: 1
I have a parent viewController say mainVC
.
On the bottom it has a tools bar subView - UIView
, with buttons.
When I press these buttons, I would like to push/transition between 3 controllers, but I would like to keep this bottom tool bar on mainVC on top all the time.
If I simply push a new controller it will cover my mainVC - hence the tool bar.
How can I get this effect programmatically ?
Upvotes: 0
Views: 60
Reputation: 271420
One way to do this is to use one view controller with the toolbar as the only subview. You can call this MyToolBarController
. Then, add a container view into MyToolBarController
.
Container views are controlled by other view controllers, so you can make one of your 3 VCs to control it. When you present a new VC, it should still be presented in the container view. Since this all happens in MyToolBarController
, the toolbar will still be there.
Upvotes: 3
Reputation: 16774
What I usually do is embed a new view controller. Basically you attach an instance of a view controller to another view controller through some view...
You need to call addChildViewController
on parent and when transitioning there are willMove
and didMove
which will trigger appropriate events on your new view controller. Otherwise you need to add the view of the view controller to the target view as a subview.
Check the following which is a stripped version of what I am using:
class ContentControllerView: UIView {
@IBOutlet weak var parentViewController: UIViewController?
private(set) var currentController: UIViewController?
private var addedConstraints: [NSLayoutConstraint] = [NSLayoutConstraint]()
func setViewController(controller: UIViewController?) {
guard let parentViewController = parentViewController else {
print("ContentControllerView error: You need to set a parentViewController to add a new view controller")
return
}
if controller?.view != currentController?.view {
currentController?.willMove(toParentViewController: nil) // Notify the current controller it will move off the parent
controller?.willMove(toParentViewController: parentViewController) // Notify the new controller it will move to the parent
if let controller = controller {
parentViewController.addChildViewController(controller) // Add child controller
}
let toRemove = addedConstraints
addedConstraints.removeAll()
controller?.view.translatesAutoresizingMaskIntoConstraints = false // Disable this to add custom constraints
if let controller = controller {
self.addSubview(controller.view) // Add as subview
addedConstraints.append(NSLayoutConstraint(item: self, attribute: .left, relatedBy: .equal, toItem: controller.view, attribute: .left, multiplier: 1.0, constant: 0.0))
addedConstraints.append(NSLayoutConstraint(item: self, attribute: .right, relatedBy: .equal, toItem: controller.view, attribute: .right, multiplier: 1.0, constant: 0.0))
addedConstraints.append(NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: controller.view, attribute: .top, multiplier: 1.0, constant: 0.0))
addedConstraints.append(NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: controller.view, attribute: .bottom, multiplier: 1.0, constant: 0.0))
// Assign new constraints
self.addConstraints(addedConstraints)
}
controller?.view.layoutIfNeeded()
self.layoutIfNeeded()
toRemove.forEach { self.removeConstraint($0) }
self.currentController?.view.translatesAutoresizingMaskIntoConstraints = true
controller?.view.frame = CGRect(x: 0.0, y: 0.0, width: self.frame.size.width, height: self.frame.size.height)
self.currentController?.view.removeFromSuperview()
self.currentController?.didMove(toParentViewController: nil) // Notify the current controller it did move off the parent
self.currentController?.removeFromParentViewController() // remove the current controller from parrent
controller?.didMove(toParentViewController: parentViewController) // Notify the new controller it did move to the parent
self.currentController = controller
self.superview?.setNeedsLayout()
(self.superview ?? self).layoutIfNeeded()
}
}
func clear() {
guard currentController != nil else {
return
}
setViewController(controller: nil)
}
}
You can use this view in code or in Storyboard. Note that parentViewController
MUST be set. So in storyboard you would add a normal UIView
above your bar and then set its class to ContentControllerView
. Then you ctrl+drag from it to its view controller and select parentViewController
.
Then in the code you can call setViewController
on it with desired view controller. In your case that is your navigation controller which will then work internally.
The stripped part is I removed everything related to animations. Consequently I am pretty sure there are some extra calls to layout in there left.
Upvotes: 1