Missing back button in nested detail view (UISplitViewController) - swift

I am trying to have nested view controllers for detail view controller of a UISplitViewController. To make things simple, I leave the master view as it is; the detail view has a button inside it, 'Go further', which segues to the second view controller. In a compact device, iPhone, everything works fine, user taps on 'Go further' and it navigates to second view controller and back button appears on top left and user can go back to the first view.
But in landscape mode for iPad, when user clicks 'Go further' button and navigates to the second view controller there is no back button up there.
It's my setup:
And the whole project is available at https://github.com/maysamsh/SplitViewWithNestedDetailViews

The root of the problem is the Navigation Controller between First One and Second One. It's not necessary, so go ahead and delete it.
Create a Push segue directly from the Go Further button to the Second One's view.
Change the prepareForSegue in FirstViewController to this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let controller = segue.destination
controller.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
controller.navigationItem.leftItemsSupplementBackButton = true
print("prepare")
}

Related

Segue push is presenting modally

I created a segue push but it presents the screen modally. Any idea why?
Tried redoing the segue and restarting Xcode but no help there.
After I linked it up via Storyboard, I named the segue in my controller and called perform when button gets tapped.
#IBAction func heyoTapped(_ sender: UIButton) {
performSegue(withIdentifier: "goToFriendList", sender: nil)
}
Select your 1st VC
Add navigation (Editor>Embed In> Navigation Controller.
Make your Navigation controller as initial view controller.
Connect your NextVC with segue (it will Push your new VC by default ), to make sure this you can select segue and make sure the “Kind” is selected as “Show (e.g. Push)”
Now give a name to the segue and do your Perform Segue.
[

Changing views programmatically

I know there are a lot of posts about this but my problem is a bit different. I have a Tab Bar Controller with multiple views and one of the views is the Login View, if the user does Login it should change the view to present the User menu.
At the same time i need to keep the Tab Bar menu visible, so i can't use modal since it will loose the reference to the Tab Bar Controller.
So i ended up using a Navigation Controller where i just push the User Menu view into the stack (not the best way but it works).
The problem is, if the user double click on the Login Bar it will load the Login View, and i don't want this to happen.
On this example, if the user clicks on the Login button it will go to the Blue view, but if the user double click on the Feature Button on the Tab Bar Menu it will go to the red view.
Since my solution does not work how can i achieve what i want? If the user press the Login button it will ONLY show the Blue view until he press the Logout button.
[Edit]
Here is the code to show the blue view:
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let ViewController = storyBoard.instantiateViewController(withIdentifier: "userViewID") as! UserViewController
self.navigationController?.pushViewController(ViewController, animated: true)
Ok i ended up checking if the Navigation Controller had more than one child (for the red one) and removing the first child from the navigation array so it could dealloc it and show only the one i wanted.
override func viewWillAppear(_ animated: Bool) {
if((self.navigationController?.viewControllers.count)! > 1)
{
self.navigationController?.viewControllers.removeFirst()
}
}
The reason i ended up doing this was because clicking 2x on the Tab Bar item it would bring me to the red view even if i had already pushed the blue view to the Navigation array.

Segue as a new view

I have a navigation controller as a root view to the home view then a sign in view then the main view. When I sign in and segue to the main view using
vc.performSegueWithIdentifier("toMenuView", sender: nil)
I can slide back to the sign in view. I don't want that. How can I segue to the main view without having access to going back unless the user taps the sign out button and then goes back to the home view without again having access to go "back" to the main view?
For gesture recogniser to swipe back to previous page.
self.navigationController.interactivePopGestureRecognizer.enabled = false
If you have a navigation bar, you might need to hide it too. Else you can also hide the back button by:
self.navigationController.navigationItem.backBarButtonItem.enabled = false

Segue from modal view to tab bar view controller and not lose tab bar

Hello Im trying to segue from a modal to a tab bar view controller without losing the tab bar? I know the question is short, but this is all I'm asking.
Scenario: I have a Tab Bar View Controllers, A and B. B modals to C view controller. Then I want to return to View Controller A.
Swift please :D
Here is my example of how to do this. In my setup, I choose the yellow ViewController from the tab, then press Go! which modally presents the white ViewController. Pressing Exit returns to the green ViewController.
To set this up, use an unwind segue to return to the viewController that called you. For instance, implement this in the first ViewController of the tab (the one calling the modal segue).
#IBAction func backFromModal(_ segue: UIStoryboardSegue) {
print("and we are back")
// Switch to the second tab (tabs are numbered 0, 1, 2)
self.tabBarController?.selectedIndex = 1
}
Then switch to another tab using self.tabBarController?.selectedIndex = n where n is the number of the tab you really want to go to. To set up the unwind segue, you can either control-drag from a button in your modal view controller to the exit icon at the top of the viewController and select backFromModal from the pop up...
OR
you can set up the unwind segue to be called programmatically by control-dragging from the viewController icon at the top of the modal viewController to the exit icon, and select backFromModal from the pop up.
Then, go to the Document Outline View and click on the unwind segue
and give it an identifier in the Attributes Inspector on the right (for example "returnFromModal").
Then you'd call the unwind segue like this:
self.performSegue(withIdentifier: "returnFromModal", sender: self)

How can I go back to the initial view controller in Swift?

So I have a login view, after successful login it goes to the first view of a navigation controller, then the user can go deeper to a settings view and then to a logout view. This logout should take the user back to the login view (which is not part of the navigation controller). It works with this code:
let loginViewController = self.storyboard!.instantiateViewControllerWithIdentifier("Login") as? LoginViewController
self.navigationController!.pushViewController(loginViewController!, animated: true)
But the login view displays the navigation bar at the top, which it shouldn't do, maybe there is something other than self.navigationController!.pushViewController that I should be using?
SWIFT: You should use an unwind segue.
First of all, put the following line in your FirstViewController:
#IBAction func prepareForUnwind(segue: UIStoryboardSegue) {
}
The function actually doesn't have any code inside it.
Now, go to your storyboard and create an unwind segue for LogoutViewController by control-dragging from the yellow button to the Exit button. Like this:
Select the unwind segue created for FirstViewController.
Change the segue identifier:
Go to the code of LogoutViewController and just call the unwind segue normally:
self.performSegueWithIdentifier("unwindToViewController1", sender: self)
Swift 4
self.performSegue(withIdentifier: "unwindToViewController1", sender: self)
If you have a Navigation controller, from your your controller use:
self.navigationController?.popToRootViewControllerAnimated(true)
Look into unwind segueing if you are working with storyboards.
You just need to create unwind option in controller, that you want navigate to:
#IBAction func unwindToMe(segue: UIStoryboardSegue){}
Then create segue from storyboard.
And when you need to navigate back, just call the performSegue method with the unwind segue identifier that you just created.
If you want to do it only from code, than you just can write something like:
let loginViewController = self.storyboard?.instantiateViewControllerWithIdentifier("Login")
UIApplication.sharedApplication().keyWindow?.rootViewController = loginViewController
In this case, you will set your app to initial state.
try it
self.view.window?.rootViewController?.dismissViewControllerAnimated(true, completion: nil)
This will get you back to the beginning of the application flow.
Updated to Swift 4 (thanks #javaBeast)
self.view.window?.rootViewController?.dismiss(animated: true, completion: nil)
self.navigationController?.popToRootViewController(animated: true)
is the best option to go to first controller of navigation controller
and then dismiss the navigation controller
I recommend you to make a segue from one ViewController to another, instead of pushing your ViewController like that.
So first, you need to Ctrl + clic from your first ViewController to your login ViewController, and then in the attribute inspector your give it an Identifier.
Then, all you have to do is this :
self.performSegueWithIdentifier("yourIdentifier", sender: self)
Now, for the navigation bar, I suggest you to remove the navigation controller from the login view, and associate it to your first view. It would remove the navigation bar from your login view.