Strange view effect when navigating and changing visibility of navigation bar - ios

I have a UINavigationController and I want its root view controller to hide the navigation bar, so I wrote this in the root view controller's class:
override func viewWillLayoutSubviews() {
self.navigationController?.setNavigationBarHidden(true, animated: false)
}
This effectively hides the navigation bar. This root view controller has a button that pushes a new view controller when tapped. I want this second view controller to show the navigation bar, so in its subclass:
override func viewWillLayoutSubviews() {
self.navigationController?.setNavigationBarHidden(false, animated: false)
}
Navigation bar is then shown, but when I tap its back button and I navigate back to the previous view controller (the one I wanted to hide the navigation bar), for an instant at the top of its view it is shown a black space where the navigation bar should be, and finally the view "goes" to the top of the screen again.
How could I avoid this effect?

Try to set the navigation bar hidden in viewWillAppear.
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated);
self.navigationController?.setNavigationBarHidden(true, animated: false)
}

Related

How to fix why status bar space behind ScrollView in Xcode?

I added a scroll view to my view which is hover the status bar (I hid it). The scroll view is working fine, but when I'm scrolling to the top, I have a white space which disappears when I tap on my screen, and appears again when I scroll down then top.
I noticed that the scroll bar is not going to the top of my view, but stopped at the status bar.
Here are screenshots which show you what I mean.
Here I'm at the top of my view but the scroll bar isn't:
Here is the same view with the white status bar which appears when I scroll top again:
It disappear when I tap on my screen or scroll down.
Here are my constraints:
I think it's a problem of Layout Margin or something like that, but I don't what I should change?
I hide the status bar like that in my view controller:
override func viewWillAppear(_ animated: Bool) {
UIApplication.shared.keyWindow?.windowLevel = UIWindowLevelStatusBar
super.viewWillAppear(animated)
}
EDIT: Even if I comment the line which hides the status bar, I still have the same problem with my scroll view. So the problem doesn't come from how I hide it.
As Sam said, I changed the content insets to "Never" on the scroll view and it works.
While unrelated to your question, I have to react to the way you hide the status bar - the proper way is to override prefersStatusBarHidden in your view controller and call self.setNeedsStatusBarAppearanceUpdate() in your viewWillAppear:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.setNeedsStatusBarAppearanceUpdate()
}
override var prefersStatusBarHidden: Bool {
return true
}
UPDATE
Since your view controller is inside of a UINavigationViewController, you need to override childViewControllerForStatusBarHidden in UINavigationViewController to use visibleViewController as the controller to determine status bar hidden (I added override to childViewControllerForStatusBarStyle for the consistence):
extension UINavigationController {
open override var childViewControllerForStatusBarStyle: UIViewController? {
return visibleViewController
}
open override var childViewControllerForStatusBarHidden: UIViewController? {
return visibleViewController
}
}

Navigation bar specific to each view controller like Apple Music

How do I have the navigation bar specific to each view controller? On the right side, the navigation bar stays with the view controller, and the left view controller has its own navigation controller. Should I just make a custom transition? Any ideas ?
Add this code in your first viewController
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.setNavigationBarHidden(false, animated: false)
}
Then add navigationBar in your viewcontrollers from storyboad. Or you can add one in viewDidLoad programmatically

swift how to push back to navigation view control

I have several view controllers and they are very complexed.
MainVC (embed with tab bar controller)
FriendListVC
ChatRoomUpperVC (embed with navigation view controller)
ChatRoomVC (NavigationViewController with embed in ChatRoomUpperVC) (only shows the tab bar)
ChatRoomQuestionVC (pushed from ChatRoomVC) (only shows the navigation bar)
MatchedWaitVC (pushed from ChatRoomQuestionVC) (hide both tab and navigation bars)
ChatVC (pushed from MatchedWaitVC) (only shows the navigation bar)
SettingVC
What I have to do is when I click the back button from the ChatVC, I should back to ChatRoomVC and show the tab bar on the bottom only.
I tried the code below but it shows the black screen and there is no tar bar neither.
override func willMove(toParentViewController parent: UIViewController?) {
if parent == nil
{
var viewControllers = navigationController?.viewControllers
viewControllers?.removeLast(3)
navigationController?.setViewControllers(viewControllers!, animated: true)
self.navigationController?.isNavigationBarHidden = true
self.tabBarController?.tabBar.isHidden = false
}
}
I guess you can use following hack to achieve what you want. In the viewDidLoad method of the ChatVC do:
override func viewDidLoad() {
super.viewDidLoad()
if let root = navigationController?.viewControllers.first {
navigationController?.viewControllers = [root, self]
}
}
This will remove the inbetween view controllers that are between ChatVC and ChatRoomVC. Now popping back (e.g. using the standard back button, or swiping from the left edge of the screen) will jump back directly to the ChatRoomVC.
EDIT
To show the tabBar again in the ChatRoomVC, add this to the viewDidAppear:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.tabBarController?.tabBar.isHidden = false
}
This will ensure that as soon as ChatRoomVC appears on the screen, its tabBar will be presented, too.

how to have the back navigation bar without the navigatin bar

I have a main page, which has a button that will go to another page.
I want when i go the second page, to have a back button at the top left of the navigation bar.
I added a navigation controller to the main view controller, and then i added a push segue to my second view controller (second page), so an automatic back button created.
what i want is that i do NOT want the navigation bar to be in the main view controller, and I don't want it to be in the second view controller, I just want to have the back button in the second view controller.
I thought about it and i came up doing:
self.navigationController?.setNavigationBarHidden(true, animated: false)
in the main view controller, that actually hide the navigation, but that makes the second view ctonroller to loose its back button.
do you have any solution to my problem?
this is the main view controller (which has the navigation bar, but i would like to not have it)
this is the second view controller, which has the back button,
I have no problem if i leave the navigatino bar, if it was transparent, any idea please? (and by transparent, i mean i can see my image bellow it)
Update 1
after the first comment gives me a hint, i tried to applied it like this:
class CustomNavigationBar: UINavigationBar {
override func drawRect(rect: CGRect) {
super.drawRect(rect)
}
}
and I set the class of my navigation bar in the UINavigationControlelr to my custom navigation bar.
and in my main view controlelr i add this:
self.navigationController?.navigationBar.translucent = true;
self.navigationController?.navigationBar.backgroundColor = UIColor.clearColor()
but the result is that my Main view controller, still has a place (though it is empty) for the navigation bar. can't i make this place as transparent to see the image bellow it?
add this to the main view controller
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: UIBarButtonItemStyle.Plain, target: nil, action: nil)
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), forBarMetrics: UIBarMetrics.Default)
self.navigationController?.navigationBar.shadowImage = UIImage()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setNavigationBarHidden(true, animated: true)
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.setNavigationBarHidden(false, animated: true)
}

Nav Bar Hidden on View Controller On Second and Subsequent Appearances

I have a parent TableViewController and a child ViewController all within the context of a navigation controller. What I want to happen is for the table view controller to NEVER show the nav bar, and for the view controller to ALWAYS show the nav bar. I hide and show the nav bar within the viewWillAppear func of each subclass, like this:
table view controller:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true);
navigationController?.navigationBar.hidden = true
UIApplication.sharedApplication().statusBarHidden=true
}
view controller:
override func viewWillAppear(animated: Bool) {
self.navigationController?.navigationBarHidden = false
}
This works for the first navigation. When I launch the app, the parent table view controller hides the nav bar, and when I select the first cell, the child view controller dutifully displays the nav bar. However, when I touch 'Back' on the nav bar, and then select the cell again, the view controller is no longer displaying the nav bar.
Is there a better way to do this?
Update - as requested attaching screenshots of XIB and Storyboard. Note that there is no XIB for the parent TableViewController. I am not confident that these screenshot will provide much insight. Especially that of the storyboard. Unfortunately, Xcode only has 2 zoom levels:
1. Too zoomed in to be useful
2. Too zoomed out to be useful
Nonetheless, here you have them:
That should work fine: When your ViewController will appear, the code should get executed every time. Try with an "print" to test if that happens.
First View Controller
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
print("viewWillLoad - Table View")
self.navigationController?.navigationBarHidden = false
}
Second View Controller
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
print("viewWillLoad - Detail View")
self.navigationController?.navigationBarHidden = true
}
Ill use that in some applications too.

Resources