Navigation Controllers in Swift - swift

I have embedded my story board view controllers with the navigation controller. However, I want one view specific controller to not have the navigation bar. How can I do this?

Hide the navigation bar in viewWillAppear.
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBarHidden = true
}
Also, make sure you have it appear again when you leave that particular view controller. I usually do this in viewWillDisappear.
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.navigationBarHidden = false
}

Related

Auto showing keyboard in swift

I need to show the keyboard automatically when I will go to a particular View controller. Let take an example I have two view controller named "A" and "B". I have a text field present in the "B" view controller. When I am navigating from "A" to "B", I need to show the keyboard automatically. How to do it?
in B view controller
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
textField.becomeFirstResponder()
}
Type it in your B ViewController
override func viewDidLoad() {
super.viewDidLoad()
self.yourTextFieldName.delegate = self
self.showKeyBoard()
}
func showKeyBoard(){
self.yourTextFieldName.becomeFirstResponder()
}

Hiding Navigation Bar in Tab Bar Controller

I have my app setup like this:
NavigationController
|-StartViewController
|-Start2ViewController
|-TabBarController
|-Tab1ViewController
|-Tab2ViewController
I want to hide navigation bar in Tab2ViewController but not in Tab1ViewController. So below is my code for Tab2ViewController:
import UIKit
class Tab2ViewController: ICPVC {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("View Wwill Appear Reached")
self.tabBarController!.navigationController!.setNavigationBarHidden(true, animated: false)
}
}
This does not work and navigation bar appears in both Tab1ViewController and Tab2ViewController, however, if I only switch the tabs' position in Interface builder so that Tab2ViewController is the first Viewcontroller in tabs, then it works and navigation bar is hidden in Tab2ViewController and visible in Tab1ViewController
Can't figure out why?

Dismiss current navigation controller when clicked tab bar

I have got a tab bar controller and in home view controller i have a navigation controller.
-Tab Bar Controller
-- HomeVC
--- VC1 navigation push -> VC2
In VC1 navigation bar is not hidden but inside VC2 is hidden. And im controlling it with viewwillappear and viewwilldisappear.
override func viewWillAppear(_ animated: Bool) {
navigationController?.navigationBar.barStyle = .blackTranslucent
}
override func viewWillDisappear(_ animated: Bool) {
navigationController?.navigationBar.isHidden = false
}
But turning back to the VC1 without swipe, I mean clicking tab bar homeVC icon hides navigation bar. I want to dismiss or pop current viewcontroller and turn back to VC1.
So you can do this by popToRootViewController of UINavigationController. you have to handle this in tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) method of UITabBarDelegate.
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
if let rootView = self.viewControllers!["Index of VC1 Controller"] as? UINavigationController {
rootView.popToRootViewController(animated: false)
}
}

Black view under navigation bar

In my app i have two view controllers embedded in navigation controller (lets say viewControllerA and viewControllerB). In the rootviewcontroller I don't want to show navigation bar, so in viewWillAppear and viewWillDisappear i have added thes lines:
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.setNavigationBarHidden(true, animated: false)
}
override func viewWillDisappear(_ animated: Bool) {
self.navigationController?.setNavigationBarHidden(false, animated: false)
}
Now from the viewcontrollerB when back button is typed under navigation bar (when it starts to disapear) black view appears. How to remove that black view?
P.S. I have set navigation bar isTranslucent to false but it does not solve the problem. In my project i'm not using storyboards.
Below answer based on the question owners test project.
From your test project you disabled the navigationController transition(view to view) animation when you hide and unhide navigation bar that causes the black view to appears.
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.setNavigationBarHidden(true, animated: true) // set to true
}
override func viewWillDisappear(_ animated: Bool) {
self.navigationController?.setNavigationBarHidden(false, animated: true) //set to true
}

interactivePopGestureRecognizer corrupts navigation stack on root view controller

In my UINavigationController I added custom back buttons with the side effect that it is not possible anymore to swipe left to right to pop the view controller and navigate back.
So I implemented interactivePopGestureRecognizer in my custom UINavigationController class:
class UINavigationControllerExtended: UINavigationController, UIGestureRecognizerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
if self.respondsToSelector(Selector("interactivePopGestureRecognizer")) {
self.interactivePopGestureRecognizer?.delegate = self
}
}
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailByGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return gestureRecognizer.isKindOfClass(UIScreenEdgePanGestureRecognizer)
}
}
This works fine except when I am in my root view controller (RVC) which is a UICollectionViewController, i.e. the most bottom view controller in the navigation stack. When I do the swipe left to right gesture, nothing seems to happen, as expected. But when I then tap a UICollectionViewCell the destination view controller (DVC) does not get pushed over the RVC. Instead I only see the DVC's shadow on the right side of the screen.
The RVC is not responsive anymore, but as I swipe left to right again, the DVC interactively moves right to left into the screen. When I finish the gesture, the DVC moves completely into the screen just to quickly disappear left to right again. The RVC becomes responsive again.
So it seems the DVC gets pushed onto the navigation stack but not visibly into the screen.
Any suggestions where this strange behaviour originates?
Implement UINavigationControllerDelegate for your navigation controller and enable/disable the gesture recognizer there.
// Fix bug when pop gesture is enabled for the root controller
func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated: Bool) {
self.interactivePopGestureRecognizer?.enabled = self.viewControllers.count > 1
}
Keeping the code independent from the pushed view controllers.
My current solution is to disable the interactivePopGestureRecognizer in the root view controller:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.navigationController?.interactivePopGestureRecognizer?.enabled = false
}
In the first child view controller I enable it again. But this seems to be more a workaround because I don't understand the actual problem why the navigation stack got messed up in the first place.
Here is my solution for this. Swift 4.2
Implement UIGestureRecognizerDelegate and UINavigationControllerDelegate protocols. In my case I did this in an UITabBarController that would be also my root view controller.
Then, on viewDidLoad, do:
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.interactivePopGestureRecognizer?.delegate = self
self.navigationController?.delegate = self
}
Then, add the delegate method for UINavigationControllerDelegate and check if it is the root view by counting the number of view on the navigation controller and disable it if it is or enable it if its not.
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
let enable = self.navigationController?.viewControllers.count ?? 0 > 1
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = enable
}
Lastly, add the UIGestureRecognizerDelegate method
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
This should fix the problem without the necessity of manually enabling/disabling the gesture recogniser in every view of your project.
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
self.interactivePopGestureRecognizer?.isEnabled = self.viewControllers.count > 1
}
Updated #rivera solution for Swift 5
Solution from Guilherme Carvalho worked for me, but I had to assign delegate methods in viewWillAppear, in viewDidLoad was too late for my implementation.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.interactivePopGestureRecognizer?.delegate = self
navigationController?.delegate = self
}
Try this code
func navigationController(navigationController: UINavigationController, didShowViewController vc: UIViewController, animated: Bool) {
self.interactivePopGestureRecognizer?.enabled = self.vc.count > 1
}