iOS 10 how to make status bar keep portrait? - ios

I want make all ViewController stay portrait except video player controller. So I made a custom navigator extended by UINavigationController.
class MyNavigationController: UINavigationController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask{
return .portrait
}
}
All is OK but status bar still rotate to landscape like this:
Anyone can help me about this? Thanks a lot and swift code will better for me.

I solved it by delete UIMainStoryboardFile in info.plist. By the way,I don't use storyboard so I add navigation controller by
self.window = UIWindow.init(frame: UIScreen.main.bounds)
self.window?.makeKeyAndVisible()
let a = ViewController()
let nav = PumpNavigationController.init(rootViewController: a)
self.window?.rootViewController = nav

Related

Swift initialize tabBarController without presenting it

The initial view controller is the tab bar controller. The tab bar is created programmatically.
Problem:
I need to load the TabBarViewController without presenting it if the boolean value loggedIn == false.
On older devices, this code works fine to never show the TabBarViewController if the user is not logged in.
However, on newer/faster devices the tab bar flashes before presenting the LogInViewController().
final class TabBarViewController: UITabBarController {
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
configureTabs()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if(!loggedIn){
let loginVC = LogInViewController()
loginVC.isModalInPresentation = true
loginVC.modalPresentationStyle = .fullScreen
present(loginVC, animated: false)
}
}
}
What is the best work around to still load the TabBarViewController but not show it if I need to present a new VC.

Changing Image Picker Preferred Status Bar Style swift

the status bar style for my application is white except when image picker controller is presented and I have already extend my UINavigationController but it doesn't seem to be working on any view present only on pushed views does anyone have solution??
extension UINavigationController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
return topViewController?.preferredStatusBarStyle ?? .lightContent
}
}
I have also try this method , but the navigationController is a let and the
preferredStatusBarStyle is read-only
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
viewController.navigationItem.title = "willShow"
navigationController.preferredStatusBarStyle = UIStatusBarStyle.lightContent
}
When you present something modally and you want it to determine the status bar style you need to set modalPresentationCapturesStatusBarAppearance = true
For example:
let navigationController = UINavigationController(rootViewController: MyViewController())
navigationController.modalPresentationCapturesStatusBarAppearance = true
present(navigationController, animated: true)
You'll also need to check if the current UINavigationController is a UIImagePickerController and return .lightContent from preferredStatusBarStyle as UIImagePickerController has a prefers the .default out of the box.
open override var preferredStatusBarStyle: UIStatusBarStyle {
if self is UIImagePickerController {
return .lightContent
}
return topViewController?.preferredStatusBarStyle ?? .lightContent
}

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
}
}

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)
}

Determine viewWillAppear from Popped UINavigationController or UITabBarController

I am unable to find a way to distinguish between popping from the Nav controller stack and entering the view controller from the UITabBarController.
I want to call a method in ViewWillAppear only when the view is presented from the TabBar, not when someone presses back in the navigation controller.
If I wasn't using a TabBarController, I could easily get this functionally using viewDidLoad.
I've tried,
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
println("View Will Appear")
if isBeingPresented() {
println("BP")
}
if isMovingFromParentViewController() {
println("from")
}
if isMovingToParentViewController() {
println("to")
}
}
But there is no difference when I present from pressing the Tab Button or when press back button.
Only the "View Will Appear" is getting called.
Using iOS 8.4 / Swift
Sounds like a good use of the UITabBarControllerDelegate.
First, add a Bool property on your ViewController comingFromTab:
class MyViewController: UIViewController {
var comingFromTab = false
// ...
}
Set your UITabBarControllerDelegate to whatever class you want and implement the method shouldSelectViewController. You may also want to subclass UITabBarController and put them in there.
func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool {
if let myViewController = viewController as? MyViewController {
myViewController.comingFromTab = true
}
If your tab's initial view controller is a UINavigationController, you will have to unwrap that and access it's first view controller:
if let navController = viewController as? UINavigationController {
if let myViewController = navController.viewControllers[0] as? MyViewController {
// do stuff
}
}
Lastly, add whatever functionality you need in viewWillAppear in your view controller:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
// ...
if comingFromTab {
// Do whatever you need to do here if coming from the tab selection
comingFromTab = false
}
}
There is no way to know for sure. So I guess the easiest way is to add some variable that you will have to change before popping back to that view controller and checking it's state in viewWillAppear.
class YourViewController: UIViewController {
var poppingBack = false
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if !poppingBack {
// your logic
}
else {
poppingBack = false // reset it for next time
}
}
}
// somewhere else in code, suppose yourVC is YourViewController
yourVC.poppingBack = true
self.navigationController.popToViewController(yourVC, animated: true)
You can also try implementing UINavigationControllerDelegate's - navigationController:willShowViewController:animated: method and check if it will be called when presenting your view controller from tab bar.
You can check parentViewController property
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if parentViewController is UITabBarController {
// Presented by UITabBarController
} else if parentViewController is UINavigationController {
// Presented by UINavigationController
} else {
// Presented by ...
}
}

Resources