I just ported my project over to Swift 2, and everything is working great - except that even the most simple segues have no back button. Here is the prepare for segue function that I am using:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if segue.identifier == "showExercise" {
if let nav = segue.destinationViewController as? UINavigationController {
if let exercisesController = nav.topViewController as? ExercisesController {
let cell = sender as! WorkoutCell
if let workout = cell.name!.text {
exercisesController.exercises = Workouts[workout]!
exercisesController.navigationItem.title = workout
}
}
}
}
}
Before, the back button to the parent segue used to automatically populate. Now, all I get is the title in the child navigation vc
Are you using show or show detail segue? It seems like you are using a modal segue. Destination view controller for show or show segue is usually the second view controller itself, and not embedded in another UINavigationController.
If your destination view controller for the show segue is really a UINavigationController, the new navigation controller's navigation bar settings may override the old one (the navigation controller of the source view controller). Try not embedding your destination view controller in another UINavigationController.
Related
I created a table view and from there let say a user pressed a cell it will go to ListTavleView but the only problem right now is that whenever a user is in ListTableView there is not back button even thought i already embed a navigation controller
and i want the fist view navigation bar is small title second view navigation bar is large title
enter image description here
Below is my code
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showList" {
if let indexPath = tableView.indexPathForSelectedRow {
let items = dataManager.items[indexPath.row]
let controller = (segue.destination as! UINavigationController).topViewController as! ListTableViewController
controller.item = items
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
}
Below is my storybord setup
Navigation bar with no back button
From the image it seems that view controller is added as a child view controller in current view controller.
There is not need to embedded navigation controller when a cell is pressed becoz there is already a navigation controller at start point so no need to create a new one.(If you present a view controller then you may need to embed navigation controller.)
So the solution is...
Delete the navigation controller.
Connect directly to the destination view controller without navigation controller as there is already.
it is better if you use pushViewController, just get a reference of the other view controller, it will always a back button since you are pushing threw navigation Controller here is a simple example:
let story = UIStoryboard(name: "Main", bundle: nil)
let vc = story.instantiateViewController(withIdentifier: "ExampleViewController") as! ExampleViewController
self.navigationController?.pushViewController(vc, animated: true)
as for the back button, the issue is with your hierarchy.
are you changing the left item of navigation bar in another view controller that might affect navigation bar in your destination view controller.
You are pushing new NavigationController(say Nav.B) to the existing one(Nav.A).
Each navigation controller keeps different navigation stack. The back button is visible when you add viewcontroller to Navigation controller. Read more about UINavigationController.
For your current scenario, you could delete the second navigation controller(i think it not essential) & connect direct segue to ListTableViewController
So this
let controller = (segue.destination as! UINavigationController).topViewController as! ListTableViewController
becomes
let controller = segue.destination as! ListTableViewController
When you need large titles(available 11+), you can add this line in viewDidLoad()
navigationController?.navigationBar.prefersLargeTitles = true
And if it needed only for this Viewcontroller, add in viewWillDisappear() or viewDidDisappear()
navigationController?.navigationBar.prefersLargeTitles = false
If you wanted to have navigation bar back button on next view, then just push the target view on navigation, it will show default navigation back button. No, need to any extra work.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showList" {
if let indexPath = tableView.indexPathForSelectedRow {
let items = dataManager.items[indexPath.row]
guard let controller = segue.destination as? ListTableViewController else {
return
}
controller.item = items
self.navigationController?.pushViewController(controller, animated: true)
}
}}
And if you are pushing the viewcontroller with segue, then no need to add below line self.navigationController?.pushViewController(controller, animated: true)
I have a Main VC which has a connection to Tab Bar Controller via segue and that Tab Bar controller has 2 sections and those are 2 ViewControllers. I need to pass data from Main VC to that specific VC which derived from Tab Bar Controller using segue. Since i am able to use only one segue (to show only TBController), is there any way to achieve to pass data directly from main to another by skipping Tab Bar controller?
Ps. Those 2 VC have a navigation controller connection between Tab Bar Controller and themselves as well.
Try This
var secondTab = self.tabBarController?.viewControllers[1] as SecondViewController
secondTab.array = firstArray
On prepare for segue function you can get the tabBar associated controllers via TabBarControllers property viewControllers - that let you select one of a tab bar controller's view controllers to become the active view controller. then you use tabBarController's property selectedIndex to actually segue to that VC.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let index = 0//the index of the tab you wish to segue to
if let bar = segue.destination as? TabBarVC {
if let nav = bar.viewControllers[index] as? UINavigationController {
if let navChildVC = navigationController.viewControllers[0] as? YourVCType { // index of the controller of enumerate to find it
// pass data to navChildVC
bar.selectedIndex = index
}
}
}
}
I have a add button on my first view controller when I navigate to the second view controller the tab bar hides. I am using prepareForSegue method to navigate to second view controller. Here is my code of prepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "AddDoc" {
let viewController = segue.destinationViewController as! UINavigationController
let destinationViewController = viewController.topViewController as! CategoryViewController
destinationViewController.doc = captureImageView.image
}
}
And I used the present modally segue to navigate. I have both my view controller embedded in navigation controller. Thank you!
Just set the dest view controller's hidesBottomBarWhenPushed property with true. destVC.hidesBottomBarWhenPushed = true
I promise that I'm completely new to Xcode and Swift, so I know I am making silly mistakes but I don't know where. This is part of my iOS app storyboard:
where the segue between the first table view and the second navigation controller is called myTaskDetailSegue and its type is Show (e.g. Push). Now I have some problems:
Neither in the first table view controller nor in the second the back button is showed and I don't know why. Many people told me that navigation bar and back button are as default in navigation controllers but they did not appear
In the class of the first table view controller here is the method prepareForSegue()
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "myTaskDetailSegue" ) {
let indexPath = self.tableView.indexPathForSelectedRow()
let task = self.taskCollection[indexPath!.row] as Task
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailsMyTasksViewController
controller.detailItem = task
println("segue mostra task \(task.id)")
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
so you can read that the segue identifier is correct but when a row is tapped nothing happens and the second table view controller is not showed.
I don't really know what I am missing because of my inexperience.
Here is the complete storyboard:
You don't need two UINavigationController's to what you want to achieve. Is important to note that every time you push(with a segue or manually) a new UIViewController it's added to the navigation stack.
According to Apple:
Pushing a view controller displays its view in the navigation interface and updates the navigation controls accordingly. You typically push a view controller in response to user actions in the current view controller—for example, in response to the user tapping a row in a table.
So you can remove the second UINavigationController in your Storyboard and make the segue directly to your DetailsMyTaskViewController and update your prepareForSegue like in the following way:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "myTaskDetailSegue" ) {
let indexPath = self.tableView.indexPathForSelectedRow()
let task = self.taskCollection[indexPath!.row] as Task
let controller = segue.destinationViewController as! DetailsMyTasksViewController
controller.detailItem = task
println("segue mostra task \(task.id)")
}
}
And your back button should appear by default as you said before. Nevertheless I strongly recommend you read the following two guides :
UINavigationViewController
View Controller Programming Guide for iOS
For a better understanding of the navigation stack, etc.
I hope this help you.
I have a set of view controllers linked to a tab controller.
When a image is selected on one of these tabbed views a segue is executed and a detail viewocntroller not linked to the tab controlled is opened.
Pronblem is when I navigate back to the tabbed view controller via segue from the detail view, the tabs are no longer visible.
Before segue executed on tabbed vc:
Same vc with no tab after segue from vc not linked to tab controller
Question is how to ensure tab will be visible on vc when called via the non tabbed vc?
Just to add the tabbed view connected to tab controller is a collection view, the detail view segue is excited when user sects an image:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
println(segue.identifier)
println(sender)
println("SEGUE SELECTED: \(segue.identifier)");
if(segue.identifier == "segueToDetailScrollView"){
// pass the cell
let cell = sender as CollectionViewCell;
let indexPath = collectionView?.indexPathForCell(cell);
let vc = segue.destinationViewController as ScrollView;
var image = arrayOfIUmages[indexPath!.row];
var imageTitle = titles[indexPath!.row];
println("Image to segue name : \(image) and the title : \(imageTitle)");
println("The vew controller \(vc)");
vc.currImage = UIImage(named: arrayOfIUmages[indexPath!.row]);
vc.textHeading = self.titles[indexPath!.row];
}
}
You will need to create a segue to the tabcontroller and let tab controllers set the inner view. Onload you can check for a shared default or something similar to find which tab should be shown.
Need to use unwind method in target view controller to allow navigation back to the same instance navigated from, good example here http://www.raywenderlich.com/81880/storyboards-tutorial-swift-part-2