Perform segue to another Navigation Controller without showing Tab Bar - ios

I have a root Tab Host Controller with two Navigation Controller tab siblings: (1) Nearby Stops and (2) Saved Stops. Each of these has a View Controller respectively.
I would like to perform a segue from one of the sibling View Controllers to another Navigation Controller with Stop Schedule View Controller embedded in it, with the following requirements:
The root Tab Bar should not show at the bottom of this View Controller
I need to pass a Stop object to this View Controller before performing the segue
Storyboard:
Currently, I am performing a segue this way, though the Tab Bar remains on the Stop Schedule View Controller when it shouldn't.
func showStopSchedule(stop: Stop) {
let stopScheduleController = self.storyboard?.instantiateViewControllerWithIdentifier("StopScheduleViewController") as! StopScheduleViewController
stopScheduleController.stop = stop // pass data object
self.navigationController?.pushViewController(stopScheduleController, animated: true)
}

You can simply set the hidden property of your tab bar when the stop schedule view controller is displayed and unhide the tab bar before that view controller disappears
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.tabBarController?.tabBar.hidden=true
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
self.tabBarController?.tabBar.hidden=false
}
Update: To animate the transition you can use this:
class StopViewController: UIViewController {
var barFrame:CGRect?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// self.tabBarController?.tabBar.hidden=true
if let tabBar=self.tabBarController?.tabBar {
self.barFrame=tabBar.frame
UIView.animateWithDuration(0.3, animations: { () -> Void in
let newBarFrame=CGRectMake(self.barFrame!.origin.x, self.view.frame.size.height, self.barFrame!.size.width, self.barFrame!.size.height)
tabBar.frame=newBarFrame
}, completion: { (Bool) -> Void in
tabBar.hidden=true
})
}
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
self.tabBarController?.tabBar.hidden=false;
if self.barFrame != nil {
UIView.animateWithDuration(0.3, animations: { () -> Void in
let newBarFrame=CGRectMake(self.barFrame!.origin.x, self.view.frame.size.height-self.barFrame!.size.height, self.view.frame.size.width, self.barFrame!.size.height)
self.tabBarController?.tabBar.frame=newBarFrame
})
}
}
}

You are not using the segue you just defined in your Storyboard. Instead, you are currently reloading your StopScheduleViewController manually, whereas you should only perform the segue you already have defined.
Add an Identifier to each of the Storyboard Segue you want to invoke programmatically,
then load them in this manner:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("showStopSchedule", sender: self)
}

If you want to only hide the navigationController the below code works.
self.navigationController?.navigationBar.hidden = true

Related

UINavigationController has to call method when updates view with a new ViewController

I have a UINavigationControllerSubclass. When view controller is popped to some new view controller (by navigationController.popViewController, navigationController.popToRootViewController or even by manually sliding from left to right)
I need to call inside my navigation controller:
viewController.newTopViewController.updateBackButtonTitle()
What is the best approach to accomplish that?
One way of doing it would be the following:
class CustomNavigationController: UINavigationController {
override func popToRootViewController(animated: Bool) -> [UIViewController]? {
shouldUpdateBackButtonTitle()
return super.popToRootViewController(animated: animated)
}
override func popViewController(animated: Bool) -> UIViewController? {
shouldUpdateBackButtonTitle()
return super.popViewController(animated: animated)
}
private func shouldUpdateBackButtonTitle() {
viewController.newTopViewController.updateBackButtonTitle()
}
}
When you return to viewController call this viewWillAppear method. Inside that function you can check your rootviewController then you can call your
updateBackbuttonTitle()<
function.
You can use viewWillAppear method, and easily update UI Controls
super.viewWillAppear(animated)

Detect when ViewController has been presented by "popping" the previous VIewController in UINavigationController [duplicate]

This question already has an answer here:
Determine is viewWillAppear comes from opening app, or deselecting modal
(1 answer)
Closed 3 years ago.
Consider the following navigation hierarchy:
NavigationContrller -> ViewController1 -> ViewController2
I'd like to detect when ViewController1 is presented by going from ViewController2, i.e. by pressing the "Back" button on the NavigationController.
The method I'm interested is - (void)viewWillAppear:(BOOL)animated. How can I check, whether the ViewController1 has been presented by going forward (i.e. NavigationController -> ViewController1) or by going backward (i.e. ViewController2 -> ViewController1)?
You can check the order of the controllers of your navigation stack in viewWillAppear like this:
for controller in self.navigationController!.viewControllers as Array {
// print("controller \(controller) at i \(i)")
}
You could use a Bool to keep track of the "push state":
class ViewController1: UIViewController {
private var isBeingPushed = true
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if isBeingPushed {
print("forwards")
} else {
print("backwards")
}
}
override func viewDidDisappear(_ animated: Bool) {
isBeingPushed = false
super.viewDidDisappear(animated)
}
override func didMove(toParent parent: UIViewController?) {
if parent == nil {
isBeingPushed = true
}
super.didMove(toParent: parent)
}
}

How do I make navigation bar to show in root viewcontroller A the second time it's presented? (A>B>A)

I'm developing a shopping list like app where I have a Navigation Controller and the root view controller is the screen where the user can search for products (SearchViewController). When the user selects a product it segues to DetailViewController. This view has an option to check out or add more products. If users click on "Add more products" I have to segue to SearchViewController so they can search for more products. I want to present this VC again but I want the Nav Bar to show this time since I want to be able to go back if I decide not to add any other products.
Right now I'm sending the shoppingContext in the segue to determine from the SearchVC if I come from "DetailsVC" or not.
I think there's a problem with the way I'm adding view controllers to the navigation stack, but I've never encountered a problem like this and don't know what else to try.
With my current implementation (performSegue from DetailsVC to SearchVC) any time I click on a new item it segues twice to the Details screen, which I suspect may also be caused by the same navigation stack issue.
I tried creating a new object of SearchVC and pushing it to the stack instead of performing the segue but it didn't work either.
What can I do to fix it?
Basically, in detailsVC I do the following:
let segueAction = SegueAction(name: "segueToSearch", preparer: {
destinationVC in
if
let activeVC = destinationVC as? SearchViewController
{
activeVC.shoppingList = self.shoppingViewModel.shoppingList
}
})
performSegue(withIdentifier: segueAction.name, sender: segueAction)
The segue "segueToSearch" is a Show (push) type segue.
Then in the SearchVC I check if shoppingList != nil and if so do:
navigationController?.setNavigationBarHidden(false, animated: false)
If I check if the navigation bar is hidden it returns false but I still don't see it.
Hi it's pretty straight forward. Answer can be found here:
Navigation bar show/hide
[[self navigationController] setNavigationBarHidden:NO animated:YES];
And I would put a property to check in the viewWillApear.
-- EDIT: --
TESTED: I added it to a button action, works also in the viewDidAppear when dismiss back from to detail.
Hope it helps.
class ViewController: UIViewController {
var didHideNav: Bool = false
#IBAction func changeHidden(_ sender: UIButton) {
if !didHideNav {
print("Should Be Hidden")
self.navigationController?.setNavigationBarHidden(true, animated: true)
didHideNav = true
}else{
print("Should Be Visible")
self.navigationController?.setNavigationBarHidden(false, animated: true)
didHideNav = false
}
}
override func viewDidAppear(_ animated: Bool) {
if !didHideNav {
print("Should Be Hidden")
self.navigationController?.setNavigationBarHidden(true, animated: true)
didHideNav = true
}else{
print("Should Be Visible")
self.navigationController?.setNavigationBarHidden(false, animated: true)
didHideNav = false
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

XLPagerTabStrip select what view controller will be shown first

I'm using XLPagerTabStrip to switch among a collection of view controllers. I have three view controllers and I would like that middle view controller is shown by default as first.
I could use
let parentViewController = self.parent! as! ParentViewController
parentViewController.moveToViewControllerAtIndex(1)
inside my first view controller, but that first view controller loads some data from the server and if I switch to another view controller while it is loading data, that first view controller will freeze and it won't load data.
Is there a way to show middle view controller as first by default?
jump to the defenition of 'currentIndex' and change it to public from private. then you can select your current controller by this code:
currentIndex = 1
In function:
override func viewControllers(for pagerTabStripController:
PagerTabStripViewController) -> [UIViewController] {
// This line will help you achieve the requirement
pagerTabStripController.currentIndex = /* required index */
}
It will work smoothly after you make currentIndex in PagerTabStripViewController as public.
To prevent loading the first tab, moveToViewControllerAtIndex() must be called before viewDidLoad() is called in your PagerTabStripViewController subclass.
override func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
pagerTabStripController.moveToViewController(at: 0) // required index
}
For Move Specific Tab XLPagerTabStrip in swift 5
override func viewDidAppear(_ animated: Bool) {
if nowFrom == "sendvc"
{
self.moveToViewController(at: 3,animated: false)
}
}
You have to use the following lines:
override func viewDidAppear(_ animated: Bool) {
self.moveToViewController(at: 2)
reloadPagerTabStripView()
}

Hide navigationBar on push not working

I'm trying to push to a viewController, however i wan't to hide the navigationBar in this viewController. However it does not seem to apply even though i've set below before pushing?
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cameraViewController = ALCameraViewController(croppingEnabled: false) { image in
// Do something with your image here.
// If cropping is enabled this image will be the cropped version
}
cameraViewController.navigationController?.setNavigationBarHidden(true, animated: false)
self.navigationController?.pushViewController(cameraViewController, animated: true)
}
the alternate way . you can directly hide/show the navigation bar on cameraViewController
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES]; //it hides
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:NO]; // it shows
}
--- In swift ---
override func viewWillAppear(animated: Bool) {
self.navigationController?.navigationBarHidden = true
}
override func viewWillDisappear(animated: Bool) {
self.navigationController?.navigationBarHidden = false
}
--- Swift 4.0 ---
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.isNavigationBarHidden = true
}
override func viewWillDisappear(_ animated: Bool) {
self.navigationController?.isNavigationBarHidden = false
}
Your code isn't working because trying to access navigationController property when it's equal to nil (quote from docs: "This property is nil if the view controller is not embedded inside a navigation controller.")
So, if you need to hide navigation bar in specified view controller use code from Keyur, or, if you can't modify code of this view controller and can't subclass it, you can hide/show navigation bar inside - navigationController:willShowViewController:animated: in your navigation controller delegate
In the storyboards you need select your ViewController and go to Editor->Embebed In->Navigation Controller. I have two Navigation Controllers, one in the root and another follow my ViewController. And the navigationBarHidden true or false, works perfectly for me, in my case.

Resources