Set NavigationBar for Destination ViewController Only - ios

I have a ViewController called SourceViewController that is embedded in a NavigationController.
SourceViewController segues to DestinationViewController upon UITableViewCell selection.
I want to hide the navigation bar on SourceViewController, but display it on DestinationViewController in order to show the Back button.
So, in SourceViewController:
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.hidden = true
}
And in DestinationViewController:
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.hidden = false
}
However, when I tap "Back" in DestinationViewController to return to SourceViewController, the navigationBar reappears in SourceViewController
The next 'obvious' step would be to set navigationBar.hidden = false in viewDidAppear in SourceViewController, however this smells for many reasons: mainly DRYness but also when returning to SourceViewController, there is a delay in hiding the navigationBar, and it is visible for a split second.
How do I solve this problem?

I think this will work, hiding the navigation bar. before appearing/disappearing the view.
override func viewWillAppear(animated: Bool) {
navigationController?.navigationBarHidden = true
super.viewWillAppear(animated)
}
override func viewWillDisappear(animated: Bool) {
navigationController?.navigationBarHidden = true
super.viewWillDisappear(animated)
}

Check ViewController lifecycle Looking to understand the iOS UIViewController lifecycle .
When you start the program viewDidLoad is called and everything is ok, but when you go back from detailController, viewDidLoad is not called, just change this line (self.navigationController?.navigationBar.hidden = true) in viewWillApear and everything must be ok.

Related

Large title to small title switch in navigation bar is not smooth iOS 13, sticky

I have a UINavigationController with default value of it's navigationBar.prefersLargeTitles = true .
I am switching that to false when I push into a new scene lets call it (DetailsViewController), by changing it into the viewWillDisappear .
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
navigationController?.navigationBar.prefersLargeTitles = false
}
Now in DetailsViewController I am using willMove(to parent:) .
override func willMove(toParent parent: UIViewController?) {
navigationController?.navigationBar.prefersLargeTitles = true
}
To transition back to large titles .
Observe the attached snapshots of how iOS 13 doing it with how iOS 12 is doing it, considering iOS 12 is the correct behavior.
iOS 13 :
iOS 12 :
What you're doing was always wrong. You should set prefersLargeTitles to true once for the navigation bar and never touch it again.
The way to change what each view controller does about large titles as it appears is that that view controller sets its own navigationItem (in its viewDidLoad) to have the desired largeTitleDisplayMode. So if the first v.c. has .always and the second has .never everything will be smooth.
Swift 5, Xcode 13:
UIViewController(1) + UINavigationController:
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.title = "Your title here"
}
UIViewController(2 - "i.e.: detailsViewController"):
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.largeTitleDisplayMode = .never
navigationItem.title = "Your title here"
}
It works like a charm!
I had the same issue and had to place a NavigationItem on the second ViewController's storyboard. My NavigationItem was being created automatically by the segue and its prefersLargeTitle in the viewDidLoad() was not finished creating before the view appeared. Adding a NavigationItem to the storyboard fixed this issue and allowed me to set the prefersLargeTitle in the storyboard's properties menu.
In my case this problem was occurring during a segue to a view controller which is a child of a UITabBarController. Setting largeTitleDisplayMode on the child view controller was not enough to fix this bug.
I have solved the issue by adding a navigation item to the UITabBarController scene and setting largeTitleDisplayMode as .never there.
I solved this problem like this:
override func viewWillDisappear(_ animated: Bool) {
title = ""
}
All ingenious is simple))
final class CustomHosting<Content: View>: UIHostingController<Content> {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationItem.largeTitleDisplayMode = .never
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationItem.largeTitleDisplayMode = .automatic
}
}
I fixed same problem like this :) My problem is presenting SUI Detail Collection view from UIKit Collection, and had some jumping while navigation title changing.

Navigation Controller & TableView: NavBar Hidden after hidden = true one time

I have a UITableView embedded in a NavigationController. The cells each link out to a larger information ViewController. For UI purposes, I hide the Navigation Bar on the TableView and show it in the InfoViewController.
The problem I am experiencing is this: upon booting the app, the NavBar is successfully hidden on the TableView. The first time I tap into a cell and open an InfoViewController, the NavBar comes back as expected. I back out of that VC and into the TableView. Again, the NavBar is hidden, as expected. If I tap into another cell, the NavBar is not displayed as expected. NOTE: This happens even when I remove any code to hide the Navigation Bar.
Here are the relevant code snippets:
TableViewController (in ViewDidLoad()):
self.navigationController?.isNavigationBarHidden = true
InfoViewController:
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.navigationBar.isHidden = false
super.viewWillAppear(animated)
}
Why would it work the first time, but not the second. Any help is appreciated!
For clarification:
App opens to TableView:
enter image description here
I click into the TableViewCell to Segue to InfoViewController:
enter image description here
I hit "Back" to go back to TableViewController. NavBar is still hidden. I click on the same cell:
enter image description here
EDITED: Messed up the TableViewController Code. Put = false instead of = true.
Also, I have one more thought, please someone check this for me. The TableViewController is inside a UIContainerView. It is almost as if when I hit "Back" I am exiting the NavigationController flow and I cannot get back in it.
Please try this code its working fine for hiding navigationBar
TableViewController
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.isNavigationBarHidden = true
}
}
InfoViewController
class InfoViewController : UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.isNavigationBarHidden = false
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.isNavigationBarHidden = true
}
}
Simple hide navigationbar again when the view controller is appear again,
do below code in tableViewController:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.isNavigationBarHidden = true
}

How do I make navigation bar to show in root viewcontroller A the second time it's presented? (A>B>A)

I'm developing a shopping list like app where I have a Navigation Controller and the root view controller is the screen where the user can search for products (SearchViewController). When the user selects a product it segues to DetailViewController. This view has an option to check out or add more products. If users click on "Add more products" I have to segue to SearchViewController so they can search for more products. I want to present this VC again but I want the Nav Bar to show this time since I want to be able to go back if I decide not to add any other products.
Right now I'm sending the shoppingContext in the segue to determine from the SearchVC if I come from "DetailsVC" or not.
I think there's a problem with the way I'm adding view controllers to the navigation stack, but I've never encountered a problem like this and don't know what else to try.
With my current implementation (performSegue from DetailsVC to SearchVC) any time I click on a new item it segues twice to the Details screen, which I suspect may also be caused by the same navigation stack issue.
I tried creating a new object of SearchVC and pushing it to the stack instead of performing the segue but it didn't work either.
What can I do to fix it?
Basically, in detailsVC I do the following:
let segueAction = SegueAction(name: "segueToSearch", preparer: {
destinationVC in
if
let activeVC = destinationVC as? SearchViewController
{
activeVC.shoppingList = self.shoppingViewModel.shoppingList
}
})
performSegue(withIdentifier: segueAction.name, sender: segueAction)
The segue "segueToSearch" is a Show (push) type segue.
Then in the SearchVC I check if shoppingList != nil and if so do:
navigationController?.setNavigationBarHidden(false, animated: false)
If I check if the navigation bar is hidden it returns false but I still don't see it.
Hi it's pretty straight forward. Answer can be found here:
Navigation bar show/hide
[[self navigationController] setNavigationBarHidden:NO animated:YES];
And I would put a property to check in the viewWillApear.
-- EDIT: --
TESTED: I added it to a button action, works also in the viewDidAppear when dismiss back from to detail.
Hope it helps.
class ViewController: UIViewController {
var didHideNav: Bool = false
#IBAction func changeHidden(_ sender: UIButton) {
if !didHideNav {
print("Should Be Hidden")
self.navigationController?.setNavigationBarHidden(true, animated: true)
didHideNav = true
}else{
print("Should Be Visible")
self.navigationController?.setNavigationBarHidden(false, animated: true)
didHideNav = false
}
}
override func viewDidAppear(_ animated: Bool) {
if !didHideNav {
print("Should Be Hidden")
self.navigationController?.setNavigationBarHidden(true, animated: true)
didHideNav = true
}else{
print("Should Be Visible")
self.navigationController?.setNavigationBarHidden(false, animated: true)
didHideNav = false
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Hide/Show TabBar in ViewController loops

Situation:
I have a few ViewControllers (all with a NavigationBar) embedded in a TabBarController. I have one specific ViewController (VC1) where I don't want to show the TabBar. From there you can go to another specific ViewController (VC2), where the TabBar needs to be shown again.
My solution:
VC1
self.hidesBottomBarWhenPushed is set to true by default
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
self.hidesBottomBarWhenPushed = false
}
override func viewWillDisappear(animated: Bool) {
self.hidesBottomBarWhenPushed = true
}
VC2
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
self.hidesBottomBarWhenPushed = true
}
override func viewWillDisappear(animated: Bool) {
self.hidesBottomBarWhenPushed = false
}
So far so good. This seems to be working, but you can push another VC1 from VC2 (Same controller with different content) and of course push another VC2 from VC1 again and so on.
The Problem:
As soon as VC2 is pushed twice from a VC1 the TabBar is always hidden.
When you hit the back button to go from a VC1 back to a VC2 the TabBar is always hidden.
Customize only VC1
override func viewWillAppear(animated: Bool) {
self.tabBarController?.tabBar.hidden = true
}
override func viewWillDisappear(animated: Bool) {
self.tabBarController?.tabBar.hidden = false
}
It is simpler architecture
Do not put the logic in viewWillDisappear or prepareForSegue since you do not know what kind of behavior the view controller that is about to be presented wants. Put the logic inside viewWillAppear instead.
Let every ViewController handle its own desired behavior and do not try to anticipate what the destination wants. Especially because you do not always know what the reason for viewWillDisappear or prepareForSegue is - therefore you cannot react accordingly.
Try change property in needed VC:
self.navigationController.toolbarHidden = YES;
Try these code in viewWillApear for hide or unhide , it'll work fine .
For VC1 : - In this you want always hide then add this code
override func viewWillAppear(animated: Bool) {
self.tabBarController?.tabBar.hidden = true
}
For VC2 : - In this you want always show then add this code
override func viewWillAppear(animated: Bool) {
self.tabBarController?.tabBar.hidden = false
}
Try this code , Its working fine . I also tried this code in sample project.

Hide navigationBar on push not working

I'm trying to push to a viewController, however i wan't to hide the navigationBar in this viewController. However it does not seem to apply even though i've set below before pushing?
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cameraViewController = ALCameraViewController(croppingEnabled: false) { image in
// Do something with your image here.
// If cropping is enabled this image will be the cropped version
}
cameraViewController.navigationController?.setNavigationBarHidden(true, animated: false)
self.navigationController?.pushViewController(cameraViewController, animated: true)
}
the alternate way . you can directly hide/show the navigation bar on cameraViewController
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES]; //it hides
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:NO]; // it shows
}
--- In swift ---
override func viewWillAppear(animated: Bool) {
self.navigationController?.navigationBarHidden = true
}
override func viewWillDisappear(animated: Bool) {
self.navigationController?.navigationBarHidden = false
}
--- Swift 4.0 ---
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.isNavigationBarHidden = true
}
override func viewWillDisappear(_ animated: Bool) {
self.navigationController?.isNavigationBarHidden = false
}
Your code isn't working because trying to access navigationController property when it's equal to nil (quote from docs: "This property is nil if the view controller is not embedded inside a navigation controller.")
So, if you need to hide navigation bar in specified view controller use code from Keyur, or, if you can't modify code of this view controller and can't subclass it, you can hide/show navigation bar inside - navigationController:willShowViewController:animated: in your navigation controller delegate
In the storyboards you need select your ViewController and go to Editor->Embebed In->Navigation Controller. I have two Navigation Controllers, one in the root and another follow my ViewController. And the navigationBarHidden true or false, works perfectly for me, in my case.

Resources