Naviagtionbar pushed up while hiding status bar - ios

In my rootViewController i have hidden status bar. When i tried to push the new viewcontroller and pop back, then navigation bar is pushed up and there is the gap between navigation bar and content view. Here are the screenshot of navigation bars.
Here is the code in rootViewController
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.statusBarHidden = true
self.navigationController?.setNavigationBarHidden(true, animated: true)
}
private var statusBarHidden = true {
didSet {
self.setNeedsStatusBarAppearanceUpdate()
}
}
override var prefersStatusBarHidden: Bool {
get {
return statusBarHidden
}
}

I resolved this issue by adding the following line to -viewDidLoad:
extendedLayoutIncludesOpaqueBars = true

Related

hidesBottomBarWhenPushed hides TabBar forever

I use Xcode 11.2 and the project minimum iOS deployment target is iOS 12.4.
I have a TabBarController on root page and on one of the tabs I have FirstViewController. When I push SecondViewController from FirstViewController, I want the tab bar to be hidden. I used hidesBottomBarWhenPushed property to hide the tab bar.
The tab bar is hidden when I push SecondViewController but when I pop the SecondViewController and move back to FirstViewController, the tab bar is still hidden.
I tried several ways to set hidesBottomBarWhenPushed to false when moving back to FirstViewController but none of the tries worked.
How can I re display tab bar when popped back to FirstViewController?
class FirstViewController: UIViewController {
#IBAction func buttonTap(_ sender: Any) {
let vc2 = SecondViewController()
// Set to Hide TabBar
hidesBottomBarWhenPushed = true
navigationController?.pushViewController(vc2, animated: true)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// This Does Not Work
hidesBottomBarWhenPushed = false
}
}
class SecondViewController: UIViewController {
/*
All The Followings Does Not Work
*/
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
hidesBottomBarWhenPushed = false
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
hidesBottomBarWhenPushed = false
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
hidesBottomBarWhenPushed = false
}
}
The key was to set hidesBottomBarWhenPushed to true from outside of the SecondViewController.
The code below was all I needed to write.
class FirstViewController {
func pushSecondViewController {
let vc = SecondViewController()
vc.hidesBottomBarWhenPushed = true // <- Here
navigationController?.push
navigationController?.pushViewController(vc, animated: true)
}
}

Smooth transition when changing navigation bar "prefersLargeTitles"

I have a view controller that is pushed onto a navigation stack. The stack has navigationBar.prefersLargeTitles = true, whilst this new view controller has navigationBar.prefersLargeTitles = false. I achieve this using the following code in the view controller that is pushed onto the stack:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationBar.prefersLargeTitles = false
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
navigationController?.navigationBar.prefersLargeTitles = true
}
However, when I return back to the presenting view controller, the change in the navigation bar from navigationBar.prefersLargeTitles = false to navigationBar.prefersLargeTitles = true is a bit glitchy. Is there any way to make this smoother?
Many thanks
Instead of directly changing the preference via the navigation controller, you should change the behavior via the navigation item of the specific view controller you would like to affect.
// Root UIViewController
class ViewControllerA: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.largeTitleDisplayMode = .always
}
}
// Pushed UIViewController
class ViewControllerB: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.largeTitleDisplayMode = .never
}
}
You can remove the lines you have in viewWillAppear and viewWillDisappear.

How can I hide the tab bar for a single view controller in a navigation controller stack

I have a UITabBarController. One of the tabs contains a UINavigationController.
I'd like to push a view controller onto the navigation stack and hide the tab bar on that view controller. I can do this easily with:
toVC.tabBarController?.hidesBottomBarWhenPushed = true
self.navigationController?.pushViewController(toVC, animated: true)
or doing it in the storyboard:
The problem is, this hides the tab bar for any subsequent view controllers I push onto the stack. I'd like to simply hide the tab bar for this one view controller and show it for all other view controllers before and after it.
There is a workaround. It works the way it is presented on gif below.
For each UIViewController that is pushed into the UINavigationController stack I override the hidesBottomBarWhenPushed property this way:
override var hidesBottomBarWhenPushed: Bool {
get {
switch navigationController?.topViewController {
case .some(let controller):
switch controller == self {
case true:
return super.hidesBottomBarWhenPushed
case false:
return false
}
default:
return super.hidesBottomBarWhenPushed
}
}
set {
super.hidesBottomBarWhenPushed = newValue
}
}
The first switch checks whether this controller belongs to some UINavigationController stack. The second switch checks whether current top UIViewController of UINavigationController stack is self.
Hope it will work in your case. Happy coding (^
If you hide on the storyboard then by this property your tab bar will hide for all the view controllers. So you can manage this by code.
You can do this programmatically by just writing one line of code in ViewDidLoad() or ViewWillAppear() method
For Swift 3:-
self.tabBarController?.tabBar.isHidden = true
And where you want to unhide the tab bar just write the following code in ViewDidLoad () or ViewWillAppear() method
self.tabBarController?.tabBar.isHidden = false
Try this in the view controller you want to hide the tab bar in:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tabBarController?.tabBar.isHidden = true
}
And this in the view controllers before and after the one you want to hide the tab bar in:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tabBarController?.tabBar.isHidden = false
}
EDIT:
Fully implemented example:
class ViewController1: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tabBarController?.tabBar.isHidden = false
}
}
class ViewController2: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tabBarController?.tabBar.isHidden = true
}
}
class ViewController3: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tabBarController?.tabBar.isHidden = false
}
}

How to hide status bar in specific view controller?

I have 3 view controllers which are added to a pageViewController so I can scroll between the 3. The issue is I want to display the status bar in only 1 of the viewControllers. So far I can hide from them all or show in them all.
I tried the following:
private var isStatusBarHidden = false {
didSet {
setNeedsStatusBarAppearanceUpdate()
}
}
override var prefersStatusBarHidden: Bool {
return isStatusBarHidden
}
How I added the VC's as child view controllers to my scroll view:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
page1 = storyboard.instantiateViewController(withIdentifier: StoryboardIdentifiers.feedViewController.rawValue) as! FeedViewController
page1.view.translatesAutoresizingMaskIntoConstraints = false
page1.delegate = self
scrollView.addSubview(page1.view)
addChildViewController(page1)
page1.didMove(toParentViewController: self)
You have 3 VC means all 3 ViewController is going to have viewDidAppear and viewWillDisappear code
override open func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
//It will show the status bar again after dismiss
UIApplication.shared.isStatusBarHidden = true
}
override open func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
//It will hide the status bar again after dismiss
UIApplication.shared.isStatusBarHidden = false
}
override open var prefersStatusBarHidden: Bool {
return true
}
Copy and paste code into those ViewController in which you want to hide your status bar.
So what it will do is inside your viewDidAppear it will hide your status bar
and as soon as we will leave the class it will set status bar visible.
In case your pageViewController is parent view then We can do it via page index
Let suppose you want to show status bar on page 2 and hide on page 1 and 3.
So we can do it, in this page
PageDataSource Function {
if(index == 1 || index == 3){
UIApplication.shared.isStatusBarHidden = true
}
else{
UIApplication.shared.isStatusBarHidden = false
}
}
override open var prefersStatusBarHidden: Bool {
return true
}
override open func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
//It will hide the status bar again after dismiss
UIApplication.shared.isStatusBarHidden = false
}
Please try this and let me know if its working or not
Thank you

status bar hidden in modal view (over fullscreen presentation)

try to hide the status bar from a modal view.
already check several methods:
override func prefersStatusBarHidden() -> Bool {
return true
}
with / without self.setNeedsStatusBarAppearanceUpdate()
also
UIApplication.sharedApplication().setStatusBarHidden(true, withAnimation: .Fade)
but depreciated in iOS 9
this works in fullscreen presentation (modal segue presentation option) but note in over full screen which is my setting.
if you have any idea..
For a non-fullscreen presentation of a View Controller, you need to use the modalPresentationCapturesStatusBarAppearance property.
e.g.
toViewController.modalTransitionStyle = .coverVertical
toViewController.modalPresentationStyle = .overFullScreen
toViewController.modalPresentationCapturesStatusBarAppearance = true
fromViewController.present(toViewController,
animated: true,
completion: nil)
For a fullscreen presentation of a View Controller, you need to:
set the new VC's modalPresentationStyle.
override prefersStatusBarHidden in the new VC
set your app plist UIViewControllerBasedStatusBarAppearance value to YES
e.g.
toViewController.modalTransitionStyle = .coverVertical
toViewController.modalPresentationStyle = .fullScreen
fromViewController.present(toViewController,
animated: true,
completion: nil)
(Yes, status bar setting in iOS is pitifully bad. It's no wonder Stack Overflow has so many questions on the subject, and so many varied answers.)
To hide the status bar when doing an over full screen modal, you need to set this in viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
modalPresentationCapturesStatusBarAppearance = true
}
Then do the standard method to hide status bar:
override var prefersStatusBarHidden: Bool {
return true
}
Indeed for FullScreen status bar update called automatically, but not for OverFullScreen.
Furthermore in my case i was need to deal with navigation controller in stack, to pass ModalViewController as child:
extension UINavigationController {
public override func childViewControllerForStatusBarHidden() -> UIViewController? {
return self.visibleViewController
}
public override func childViewControllerForStatusBarStyle() -> UIViewController? {
return self.visibleViewController
}
}
Inside ModalViewController we manually update status bar, also in order to make it smooth we have to do that in viewWillDisappear, but at that point visibleViewController still ModalViewController, nothing left as to use internal bool statusBarHidden and update it accordingly
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.statusBarHidden = true
self.setNeedsStatusBarAppearanceUpdate()
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
self.statusBarHidden = false
self.setNeedsStatusBarAppearanceUpdate()
}
override func prefersStatusBarHidden() -> Bool {
return self.statusBarHidden
}
If you are using a storyboard and you want to hide/show the status bar, you can use this method on previous view controller:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
UIApplication.shared.setStatusBarHidden(false, with: UIStatusBarAnimation.none)
}

Resources