Reputation: 335
I have the scheme: UITabBarViewController
(with 3 tabs).
In all that tabs I don't want to show navigation menu on top.
And from the first tab, I want to push another view controller from button click that will have "back" button (and top toolbar with "cancel")
I tried some ways - in storyboard
with push segue - no back button.
Probably because i don't have navigation view controller, so my navigation stack is empty.
Programmatically:
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "AddCoinTableViewController") as! AddCoinTableViewController
self.present(nextViewController, animated:true, completion:nil)
If I embed tabs in navigation controller, then I have top toolbar (which I don't want).
Any ideas how to make it?
Upvotes: 4
Views: 6585
Reputation: 2154
You can't achieve navigation functionality without using UINavigationController
. I mean you have to do all animation kind of stuff on your own, and I think that's not a good idea. Rather than that, you can use UINavigationController
, and if you don't want to show navigationBar
at some viewController, than do as follows for those view controllers.
override func viewWillApear() {
super.viewDidLoad()
self.navigationController?.isNavigationBarHidden = true
}
override func viewWillDisappear(animated: Bool) {
self.navigationController?.isNavigationBarHidden = false
}
Upvotes: 10
Reputation: 23498
The below code will allow you to create your own Navigation handling class and have the "push" "pop" animation that UINavigationController
has.. You can create a new project, copy paste the below into ViewController.swift
and see for yourself..
Now you can give any UIViewController
navigation controller abilities..
import UIKit
class NavigationHandler : NSObject, UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning, UINavigationBarDelegate {
private var isPresenting: Bool = false
private weak var controller: UIViewController?
init(controller: UIViewController) {
super.init()
self.controller = controller
controller.transitioningDelegate = self
let navigationBar = UINavigationBar()
controller.view.addSubview(navigationBar)
NSLayoutConstraint.activate([
navigationBar.leftAnchor.constraint(equalTo: controller.view.leftAnchor),
navigationBar.rightAnchor.constraint(equalTo: controller.view.rightAnchor),
navigationBar.topAnchor.constraint(equalTo: controller.view.safeAreaLayoutGuide.topAnchor)
])
navigationBar.translatesAutoresizingMaskIntoConstraints = false
navigationBar.delegate = self
let item = UINavigationItem(title: controller.title ?? "")
let barButton = UIBarButtonItem(title: "Back", style: .done, target: self, action: #selector(onBackButton(button:)))
item.leftBarButtonItems = [barButton]
navigationBar.setItems([item], animated: true)
}
func position(for bar: UIBarPositioning) -> UIBarPosition {
return .topAttached
}
@objc
private func onBackButton(button: UIBarButtonItem) {
self.controller?.dismiss(animated: true, completion: nil)
}
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
self.isPresenting = true;
return self;
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
self.isPresenting = false;
return self;
}
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.25;
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let duration = self.transitionDuration(using: transitionContext)
let fromController = transitionContext.viewController(forKey: .from)
let toController = transitionContext.viewController(forKey: .to)
let containerView = transitionContext.containerView
if self.isPresenting {
let frame = fromController!.view.frame
containerView.addSubview(toController!.view)
toController?.view.frame = CGRect(x: frame.origin.x + frame.width, y: frame.origin.y, width: frame.width, height: frame.height)
UIView.animate(withDuration: duration, animations: {
fromController?.view.frame = CGRect(x: frame.origin.x - frame.size.width, y: frame.origin.y, width: frame.size.width, height: frame.size.height)
toController?.view.frame = frame
}, completion: { (completed) in
transitionContext.completeTransition(true)
})
}
else {
let frame = fromController!.view.frame
containerView.insertSubview(toController!.view, at: 0)
toController?.view.frame = CGRect(x: frame.origin.x - frame.size.width, y: frame.origin.y, width: frame.size.width, height: frame.size.height)
UIView.animate(withDuration: duration, animations: {
fromController?.view.frame = CGRect(x: frame.origin.x + frame.width, y: frame.origin.y, width: frame.width, height: frame.height)
toController?.view.frame = frame
}, completion: { (completed) in
transitionContext.completeTransition(true)
})
}
}
}
View Controllers for testing:
class ViewController : UIViewController {
private var navigationHandler: NavigationHandler?
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(type: .custom)
button.setTitle("Push Controller", for: .normal)
button.setTitleColor(UIColor.red, for: .normal)
button.layer.borderColor = UIColor.black.cgColor
button.layer.borderWidth = 1.0
button.layer.cornerRadius = 5.0
button.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(button)
NSLayoutConstraint.activate([
button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
button.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
button.heightAnchor.constraint(equalToConstant: 45.0),
button.widthAnchor.constraint(equalToConstant: 150.0)
])
button.addTarget(self, action: #selector(onPush(button:)), for: .touchUpInside)
}
@objc
private func onPush(button: UIButton) {
let child = ChildViewController()
self.navigationHandler = NavigationHandler(controller: child)
self.present(child, animated: true, completion: nil)
}
}
class ChildViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.blue
}
}
Upvotes: 2
Reputation: 3256
You can embed the navigation controller at your first tab controller (or any you want), and hide it at the controllers you don't want on their viewDidLoad like this:
self.navigationController?.isNavigationBarHidden = true
Doing this, you will be able to see the back Button at the controllers you pushed and didn't hide the navigationBar.
Make sure you push the controller using the navigation controller like this:
self.navigationController?.pushViewController(YOUR VIEW CONTROLLER, animated: true)
Upvotes: 2