Navigation bar not working properly under UIPageController? - ios

I am trying to implement pagination in my application.
for that, I have created one UIPageViewController and added multiple view controller under the UIPageViewController.
for adding controller in UIPageViewController, I have used following code.
let page1: SPWalkController! = self.storyboard!.instantiateViewController(withIdentifier: "walkid") as! SPWalkController
let page2: SPCreateWalkController! = self.storyboard!.instantiateViewController(withIdentifier: "createwalkid") as! SPCreateWalkController
page1.isCreateWalk = true
pages.append(page1)
pages.append(page2)
// Create the page container
pageContainer = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
pageContainer.delegate = self
pageContainer.dataSource = self
pageContainer.setViewControllers([page1], direction: UIPageViewControllerNavigationDirection.forward, animated: false, completion: nil)
// Add it to the view
view.addSubview(pageContainer.view)
but the problem is added controller view showing under the navigation bar.
for that reason, I have deselected property "Under top bar" of Container controller. So my issue resolved. but when I have tried to present another view controller on that view controller and dismissed it again it shows it's sub view controller under the navigation bar.
Here are my screenshots of facing issue
First screenshot before present another view controller on it
presented another viewcontroller
After dismissal above view controller it looks like following.
The view goes under the navigation bar
How can I resolve this issue? or implement UIPageViewController is there any guideline?

I found a solution myself. I have presented view controller on root view controller. so now it is working properly.
[self.view.window.rootViewController presentViewController:navigationController animated:YES completion:nil];

Related

Modal presentation style from view controller embedded in a full screen navigation controller

I have a view controller embedded in a navigation controller. I settled the navigation controller modal presentation full screen:
let firstVC = FirstViewController()
customNavigationController = CustomNavigationController(rootViewController: firstVC)
customNavigationController.modalPresentationStyle = .fullScreen
self.navigationController.present(customNavigationController, animated: true, completion: nil)
In the "firstVC" I need to present another view controller with modal presentation style .pageSheet:
class FirstViewController {
func presentSecondVC() {
let secondVC = UIViewController()
secondVC.modalPresentationStyle = .pageSheet
present(secondVC, animated: true, completion: nil)
}
}
The result is this.
This is not what I want. I want the default presentation, like this.
My problem is that I need the full screen presentation for all the controllers that will be presented in the flow, but only in one case I need the pageSheet presentation with the default iOS graphic.
Is that possible?
I think that default tools cannot help you. And way to try to manage presenting view is not good idea.
So one way to get what you want is to make custom view like standard .pageSheet view, and then you present it with .fullScreen modal presentation.

What is different between this when we navigate one view controller to another

What is the difference between this first call:
let next = self.storyboard?.instantiateViewController(withIdentifier: "AFVC") as! AddFileViewController
self.present(next, animated: true, completion: nil)
and this second:
let dashboard = self.storyboard?.instantiateViewController(withIdentifier: "DBVC") as! DashboardViewController
self.navigationController?.pushViewController(dashboard, animated: true)
The first usage will present the new view controller. This presentation normally slides the new controller up from the bottom. If you want to go back, you need to create a button or something similar to dismiss it.
The second usage will use the navigation controller to display (via push which normally slides in from the right) the new view controller. You will automatically get a "< Back" button in the navigation bar. But this will only work if the calling view controller is already embedded in a navigation controller, otherwise self.navigationController is nil.

Setting back button when presenting a view controller

On clicking a button I display a view controller using the following code:
let navController = UINavigationController(rootViewController: locationVC)
navController.navigationBar.barTintColor = StyleHelper.navBarColor()
navController.navigationBar.tintColor = UIColor.whiteColor()
navController.navigationItem.backBarButtonItem = UIBarButtonItem(image: UIImage(named: "back_arrow"), style: .Plain, target: locationVC, action: nil)
self.presentViewController(navController, animated: true, completion: nil)
But the back button does not appear on the locationVC
What am I doing wrong? Please help
Multiple issues with code.
Issue 1:
You should update viewController's bar button item and not navigationController's bar button item.
So this is wrong
navController.navigationItem.backBarButtonItem
Whats correct
self.navigationItem.backBarButtonItem
Issue 2:
The above code won't work because your current viewController is not pushed by any other VC so it cant show back button. What you need is leftBarButtonItem
So in your VC you can write
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Abcd", style: .done, target: self, action: yourSelectorHere)
}
O/P:
Back button only appears for view controllers in the navigation stack.
you creating new navigation controller stack and making locationVC as root controller so there won't be any view controller to go back.
If you push another view controller to the navigation stack then you will get back button.
In a horizontally regular environment, the view controller is
presented in the style specified by the modalPresentationStyle
property. In a horizontally compact environment, the view controller
is presented full screen by default. doc: presentViewController
So, if you use present a view controller it will not show in navigation controller thus no back button
For this case you need to push view controller.
From storyboard:
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyBoard.instantiateViewController(withIdentifier:
"newViewController") as! YourViewController
self.navigationController?.pushViewController(vc, animated: true)
Programmatically
let vc = YourViewController()
self.navigationController?.pushViewController(vc, animated: true)
presenting will present your VC on top of everything and not push it to the navigayionCOntroller.
You should push your VC to the NavigationController instead like so:
var rootViewController = self.window!.rootViewController as UINavigationController
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var profileViewController = mainStoryboard.instantiateViewControllerWithIdentifier("profile") as ProfileViewController
rootViewController.pushToViewController(profileViewController, animated: true)
presentViewController is a method that bring a modal view to your navigation, not part of the navigationController.
Instead you should use the pushToViewController method on the navigationController (and not creating a new one) like that :
if let navigationController = self.navigationController {
navigationController.pushViewController(locationVC, animated: true)
}
The presenting view controller is responsible for dismissing the view controller is presented. If you call this method on the presented view controller itself, UIKit asks the presenting view controller to handle the dismissal.
If you present several view controllers in succession, thus building a stack of presented view controllers, calling this method on a view controller lower in the stack dismisses its immediate child view controller and all view controllers above that child on the stack. When this happens, only the top-most view is dismissed in an animated fashion; any intermediate view controllers are simply removed from the stack. The top-most view is dismissed using its modal transition style, which may differ from the styles used by other view controllers lower in the stack.
If you want to retain a reference to the view controller's presented view controller, get the value in the presentedViewController property before calling this method.
#IBAction func backButtonAction(_ sender: UIButton) {
self.dismiss(animated: true)
}
More: https://developer.apple.com/documentation/uikit/uiviewcontroller/1621505-dismiss

UINavigationController Within UIPageViewController Issue

I've searched and searched still cannot figure out how to fix my problem. I have a UIPageviewController as the initial view controller (like Tinder style). I want each viewController child (page) to be embedded within their own UINavigationController, so basically the page view controller will add the UINavigationController as it's child view controller. And I'm using the setViewController method when a user taps a button in it's child view controller's navigation controller to move to the next view controller by getting a reference to the parent pageviewcontroller, as opposed to using the pageviewcontroller datasource. I don't want to use the pageviewcontroller's datasource because I don't want the swiping gesture.
However, when the user taps the button in the child's navigation controller to trigger it's parent pageviewcontroller to set the next controller, which is also a UINavigationController, the animation of doing this makes the whole screen jump up and then down. If I remove the navigation controller and just send the view controller child instead, then it works fine. Does anyone know why embedding a navigation controller inside a pageviewcontroller would cause this issue?
Here's the code used when a user taps the bar button item in the navigation controller's navigation bar:
func pageViewControllerSetNewControllerFoward() {
print("page view controller set matches")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let matchesController = storyboard.instantiateViewController(withIdentifier: "matchesNav") as! UINavigationController
parentPageViewControllerReference.setViewControllers([matchesController], direction: .forward, animated: true, completion: nil)
}
The likely culprit of this behaviour is the UINavigationControllertrying to set it's own UINavigationBar. Try setting the
self.navigationController?.setNavigationBarHidden(true, animated: false)
in the viewDidLoad() of your UINavigationController
This can be solved by setting Automatically Adjust Scroll Views to false for the PageViewController and NavigationViewControllers.
Do so by self.pageViewController.automaticallyAdjustsScrollViewInsets = false or easier still in Interface Builder under attributes>layout>Adjust Scroll View Insets set to false.

Navigation Bar Not Showing after Adding NavigationController

I have an existing UITableViewController that I've embedded in a NavigationController. However, the Navigation Bar is not showing when I present the view.
Presenting the TableViewController (its Storyboard id is: SelectServicesController) :
if let selectServicesController = self.storyboard?.instantiateViewControllerWithIdentifier("SelectServicesController") as? UITableViewController {
self.navigationController?.presentViewController(selectServicesController, animated: true, completion: nil)
}
This is what it looks like when I build (nav bar does not show):
So I just did this and at fist could not get it to show up at all. Then Figured it out, You just need to select the navigation controller and set it to be the ✅is initial View Controller
This is what your storyboard should look like
Then to make everything show up I added this to my viewDidLoad of the view the Navigation controller is presenting. This step is more optional.
self.navigationController?.navigationBar.barTintColor = UIColor.redColor()
self.navigationController?.navigationBar.tintColor = UIColor.blackColor()
self.navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.blackColor()]
navigationController?.navigationBar.hidden = false
And this is what it looks like
mmmm Red on black 🤓 Hope that helps you.
You're presenting a UITableViewController, which doesn't have a navigation controller as a parent (even though your Storyboard has it first, you're not actually using it).
You can fix this by doing something like this:
if let selectServicesController = self.storyboard?.instantiateViewControllerWithIdentifier("SelectServicesController") as? UITableViewController {
let navigationController = UINavigationController(rootViewController: selectServicesController)
self.navigationController?.presentViewController(navigationController, animated: true, completion: nil)
}
Or by setting the navigation controller as the initial view controller of the storyboard and then calling it like this:
if let selectServicesController = self.storyboard?.instantiateInitialViewController() {
self.navigationController?.presentViewController(selectServicesController, animated: true, completion: nil)
}
I encountered the same problem. I solved it by Changing the segue to the navigation controller that embeds the View Controller I want to display.
Hopefully it would work for you.
Let me know if it is a bad practice.
let storyboard = UIStoryboard(name: "Expense", bundle: Bundle(for: PTCAddExpenseViewController.self))
let controller = storyboard.instantiateViewController(withIdentifier:"AddExpense") as! PTCAddExpenseViewController
let navigationController = UINavigationController(rootViewController: controller)
self.present(navigationController, animated: true, completion: nil)
Adding this works for me:
self.navigationController?.isNavigationBarHidden = false
You're presenting the table view controller directly, not its navigation controller. If you mark the nav controller as the initial view controller (tick the "Is initial view controller" box in the attributes inspector), then you can instantiate and show it by:
if let selectServicesNavController = self.storyboard?.instantiateInitialViewController() as? UINavigationController {
// if you're pushing it onto an existing nav controller
self.navigationController?.presentViewController(selectServicesNavController, animated: true, completion: nil)
// if not (and this is probably the case), set the nav controller as your window's rootViewController
UIApplication.sharedApplication().keyWindow.rootViewController = selectServicesNavController
}
My guess is Xcode is ignoring the fact that your table view controller is embedded in navigation controller when presenting your table view controller with the following code:
if let selectServicesController = self.storyboard?.instantiateViewControllerWithIdentifier("SelectServicesController") as? UITableViewController {
self.navigationController?.presentViewController(selectServicesController, animated: true, completion: nil)
}
Instead, I would suggest you modify the Top Bar setting under Simulated Metrics to suit your needs or instantiate your navigation controller instead (the latter is preferred and recommended)
In your code, change this line
self.navigationController?.presentViewController(selectServicesController, animated: true, completion: nil)
to this
self.presentViewController(selectServicesController, animated: true, completion: nil)
I read in one of your comments you want to present the table view controller modally, with the navigation bar showing. We can do this using the Storyboard. From the view controller that should display this table view controller modally, Ctrl+Drag from the view controller to the Navigation Controller of the Table View Controller. Then, select Present Modally. Set an Identifier for the segue. Then, in your code for the view controller that is presenting the table view controller modally, call:
self.performSegueWithIdentifier("YourSegueIdentifier", sender: nil)
Another way to do this without having to use any code is if the modal presentation is being triggered by something like a button. Then, you can Ctrl+Drag from that button to the Navigation Controller and select Present Modally.
Or it might be this!!
I had the same problem: the navigation bar was showing on the root view in Storyboard, but when running the Simulator - there was no navigation bar at the top of the views. This solved it:
Navigation Controller > Navigation Bar > UNCHECK Translucent (it is checked by default). This did two things:
My Navigation Bar shows on all subsequent views.
The topmost subview is now at Y=0, and not Y=64.

Resources