hiding my NavigationBar with this :
func hideAndShow(){
if self.navigationController?.navigationBar.hidden == true {
self.navigationController?.setNavigationBarHidden(false, animated: true)
}else {
self.navigationController?.setNavigationBarHidden(true, animated: true)
}
}
but its also lifting up my View (maybe because View is below the Navigation), how can i hide it without lifting up my View
see the below image for better understanding
as you can see that my image in my view also get shifted up while hiding the NavigationBar any idea how can i fix this ??
can we just show the view below the layer of navigation bar ???
Two steps are required to solve your problem:
Add self.edgesForExtendedLayout = UIRectEdge.All to viewWillAppear. As a result your view will start at the top of the screen instead of below the NavigationBar. You can read more about edgesForExtendedLayout here: https://stackoverflow.com/a/19585104/1447641
Add a top constraint of {navigationbarheight} to your ImageView.
After that the position of the ImageView shouldn't be effected by the NavigationBar anymore.
Related
I have a UINavigationController with some UIViewControllers embed. The problem is when I start to push viewControllers. As you can see in the next image, the content view of the current viewController is overlapping the navigationBar:
In viewDidLoad:
func setupFront() {
navigationController?.setNavigationBarHidden(false, animated: true)
self.navigationController?.navigationBar.prefersLargeTitles = true
title = NSLocalizedString("customer_settings_profile_title", comment: "")
binding()
setupLanguage()
}
The problem was the autolayout. The top constraints of the views that I push weren't set to safe area.
Now it is and it works:
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
}
}
I have two viewcontrollers. The first viewcontroller is collection view controller and i set self.navigationController?.hidesBarsOnSwipe = true in viewDidLoad().
When I push the second viewController from the visible cell of collectionView, the navigation bar is showing in the second viewController but if I scroll the collectionView cell and when push the navigation is not showing.
Can anyone tell me what the problem is?
scrolling is done via swipe gesture, so it triggers your code:
self.navigationController?.hidesBarsOnSwipe = true
because navigation controller is shared between all view controllers presented on top of it, it's properties (like hidden bar) preserves pushing / popping.
Common pattern is to change it's state in overrided lifecycle methods, eg:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.hidesBarsOnSwipe = false
self.navigationController?.setNavigationBarHidden(false, animated: true)
}
and reverting those state in viewWillDisappear
When this property is set to true, an upward swipe hides the navigation bar and toolbar. A downward swipe shows both bars again. If the toolbar does not have any items, it remains visible even after a swipe. The default value of this property is false. (get it from apple)
See the doc https://developer.apple.com/documentation/uikit/uinavigationcontroller/1621883-hidesbarsonswipe
It means when you swipe up it will hide and when swipe down it will shown. That's the reason.
To fix it you can add following code to the other controller
[self.navigationController setNavigationBarHidden:NO animated:YES];
Don't get much insight what exactly you implemented, but try to unhide navigation bar in second view controller.
Add below code in viewDidLoad method of second View controller.
self.navigationController?.isNavigationBarHidden = false
Put this self.navigationController?.hidesBarsOnSwipe = false and this self.navigationController?.setNavigationBarHidden(false, animated: true) in your second view controller.
You might want to move your self.navigationController?.hidesBarsOnSwipe = true from viewDidLoad to viewWillAppear in your first view controller.
I am hiding my navigation bar when I scroll by calling: self.navigationController?.setNavigationBarHidden(true, animated: true)
The only problem is that the navbar doesnt get hidden all the way.
Whats even stranger is if I push to a new VC and go back and now try to scroll the navigation bar gets hidden all the way which is what I want.
If it matters I am hiding the navigation bar on VC2 then showing it when I exit back to VC 1.
This is what it looks when I try to hide the navbar first time, it doesnt go up all the way/underlying view showing too much.
If I push the to next VC and go back and now try to hide the navigationbar it works
The my view has a constraint of 0 to top layout so its hugging the top
So how can I make my view always be like in the second image when hiding my navigation bar?
Try this code...
Note: This is a simple approach for your problem. If you want more custom look navBar and status bar look .You should read my previous comment...
Set navigation controller property hidesBarsOnSwipe to true
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
navigationController?.hidesBarsOnSwipe = true
}
I understand your question.
The green part in your second image is not a navigation bar, it is a status bar.
You can hide the status bar as below.
You should implement prefersStatusBarHidden on your view controller(s):
In Swift 2:
override func prefersStatusBarHidden() -> Bool {
return true
}
In Swift 3:
override var prefersStatusBarHidden: Bool {
return true
}
I have an App using a Tabbar for basic Navigation. From one of the screens of the Tabbar I want to enter another one that shows a toolbar instead of the Tabbar and a back navigation item on the top.
What is the best way to do this? If I use "Hide Bottom Bar on Push" (aka hidesBottomBarWhenPushed) and add a Toolbar to the screen I can see an animation removing the Tabbar before the Toolbar is placed at the bottom of the screen.
Solution for UITableViewController with toolbar (requires code)
Using code from this answer, I was able to achieve the same effect, but with the toolbar at the bottom of a table view.
Add this to your table view controller:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setToolbarHidden:NO animated:YES];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.navigationController setToolbarHidden:YES animated:YES];
}
Important note: placing these calls in viewWillAppear and viewWillDisappear instead of viewDidLoad makes this easier to handle, as it will work reliably even for multiple pushes and pops of the same view controller, and you won't have to clean up after it in the previous view controller.
And configure it like this in the storyboard:
Also, enable Hides bottom bar when pushed in the storyboard, or in your code, for the view controller being pushed.
Then you can add toolbar buttons to the toolbar in the storyboard.
Build and run, and you get this effect:
Here's a complete sample project demonstrating this.
Problem Example
Here is my solution,
In the first view controller that has the tabbar do this
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "someSegue" {
if let secondVC = segue.destinationViewController as? InfoTableViewController {
secondVC.hidesBottomBarWhenPushed = true
}
}
}
I also needed this, as my toolbar would re appear in the first VC.
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
navigationController?.toolbarHidden = true
}
To stop the fade up animation of the toolbar, so its just there i used this in the second VC
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.toolbarHidden = false
}
Pure storyboard solution
If you're referring to the issue of the toolbar appearing above the tab bar during the push transition animation, I was able to fix this by adjusting the auto layout constraints on the toolbar in the storyboard (add it manually to your view controller; see my other answer if you're using a UITableViewController or UICollectionViewController and can't do this):
Add a constraint to set the distance to the bottom layout guide to zero:
Double click that constraint to edit it, and set the first item to Bottom (it will be Top by default).
All done! This will result in an effect like this:
Here's my sample project that demonstrates this working as expected. Note that I didn't change any of the code, everything is in the storyboard.
As of Xcode 7, the pure Storyboard solution doesn't work anymore because Xcode wouldn't let you assign the Bottom attribute to the Bottom Layout Guide anymore.
For my project, I used the following setup:
A UITabBarController as initial view controller, going into a
UINavigationController, with root vc set to...
UIRegularViewController, which should behave normally, but spawn a...
UISpecialViewController, which should hide the tab bar and instead display a toolbar. Also, it should hide the status bar, the navigation bar and the tool bar on tap.
Here is what I did to achieve this:
In the storyboard
UITabBarController: set Tab Bar Translucency to NO
UISpecialViewController: Set Simulated Metrics like so
Status Bar: None
Top Bar: Opaque Nav Bar
Bottom Bar: Opaque Toolbar
Set Extended Edges like this:
Under Top Bars: NO
Under Bottom Bars: YES
Under Opaque Bars: YES
Do not drag a UIToolBar into UISpecialViewController !
In the Implementations
// in UISpecialViewController.m
- (void)viewWillAppear:(BOOL)animated {
self.navigationController.toolbarHidden = NO;
self.navigationController.hidesBarsOnTap = YES;
}
- (void)viewWillDisappear:(BOOL)animated {
self.navigationController.toolbarHidden = YES;
self.navigationController.hidesBarsOnTap = NO;
}
- (BOOL)prefersStatusBarHidden {
return self.navigationController.navigationBarHidden;
}
Here is the Demo Code.
This is the result:
In fact, UIKit has already configured how Toolbar and Tabbar change in the page switching animation.
I also have this situation with you today, and the final solution surprised me.
For example, page A to page B, page A displays Tabbar, not Toolbar, page B does not display Toolbar, and does not display Tabbar.
At this time, B needs to set hidesBottomBarWhenPushed to true, which is necessary.
Then, in the declaration cycle of the two ViewControllers, in the viewWillDisappear of A and the viewWillAppear of B, if you set the navigation controller setToolbarHidden, this animation problem will occur.
If you set it in viewDidDisappear of A and viewDidAppear of B, the problem is solved. Although the toolbar will have a delayed animation, it is always better than the wrong animation.
Finally add:
The order of A and B life cycle function calls is:
A - viewWillDisappear
B - viewWillAppear
A - viewDidDisappear
B - viewDidAppear
These four methods are interleaved.
Using Xcode 12.4 iOS 14.4
for those who struggle with this issue and try solutions above with no luck.
let's say A is with tabBar only, B is only showing toolbar
remember to set hidesBottomBarWhenPushed = true in B's init
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
hidesBottomBarWhenPushed = true
}
implement these below in B. (no need to do anything in A)
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.setToolbarHidden(true, animated: false)
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
navigationController?.setToolbarHidden(false, animated: false)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
navigationController?.setToolbarHidden(true, animated: true)
}
that's it!!
p.s. if you want to remove the toolbar animation from bottom up then add this
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
navigationController?.toolbar.layer.removeAnimation(forKey: "position")
}