I have a popover view which is simply a stack of UIButtons.
The popover is presented from a view controller (Records) which is itself inside a NavigationController.
I need the buttons in popover view to be able to push other views on top of the navigation stack.
Here's how I prepare the segue for the popover in the Records view controller:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "popoverSegue" {
let dest = segue.destination as! PopoverViewController
dest.navController = navigationController
dest.modalPresentationStyle = .popover
dest.popoverPresentationController?.barButtonItem = addButton
dest.popoverPresentationController?.delegate = self
}
}
Then inside the popoverViewController I got a bunch of IBAction functions where I need to push other views on top of the navController that was set above.
let editor = EditorViewController(nibName: "EditorViewController", bundle: nil)
navController?.pushViewController(editor, animated: true)
This kina works and the editor view shows up with a nav bar and all, but as soon as I tap on the view or try to scroll, it just gets dismissed.
How can I prevent that dismiss thing? I did try setting isModalInPresentation. It didn't work for me.
Answering, as per OP's comments...
The proper approach is to have your "popover" controller tell the presenting controller to push a new VC onto the navigation stack.
This can be done in a few different ways, but most commonly by using either the protocol/delegate pattern or with closures.
Related
In my iOS app, in a viewController I try to open a specific view in Tab Bar Controller.
I use a performSegue.
First I try to navigate straight to the specific view , but in this case the tab bar disappear
So I try to navigate to the tabViewController, and this lead me to the defult view (the first)
any idea how to navigate to a specific view in TabBarController ?
the performSegue I use:
self.performSegue(withIdentifier: "goToMain", sender: self)
//"goToMain" is my indentipier to the storyboard Segue
I use swift 4
with this code, you don't need segues, you can use when you push some button
let VC1 = self.storyboard!.instantiateViewController(withIdentifier: "tabBarController") as! tabBarLoginViewController
VC1.selectedIndex = 2 //this line says that the view that appears will be third of you tab bar controller
self.navigationController!.pushViewController(VC1, animated: true)
if you want to use segue use this, the segue needs to point of tab bar controller, not a view of tab bar controller
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "goToMain") {
let vc = segue.destination as! TabBarController
vc.selectedIndex = 2
}
}
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 View Controller embedded in a Nav Controller for use with AWS Cognito.
I then have a separate stack that's segued to from the initial VC.
I have the 2nd stack embedded in its own Nav Controller, and I've tried push, show, and present modally. Each time I attempt to segue to the new Nav Controller, the segue is performed, then the new stack pops off, and I'm presented with the initial VC. Here's how my storyboard is set up:
Here's my prepare for segue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "FindTruth" {
if let findTruthVC = segue.destination as? FindTruth {
if let user = sender as? User {
if let userDetails = self.userDetails {
user.userDetails = userDetails
print("User Details: \(userDetails) passed")
}
findTruthVC.user = user
print("User: \(user.userId) passed")
}
}
}
}
Calling the segue:
self.performSegue(withIdentifier: "FindTruth", sender: self.user)
There's no code nor storyboard reference from the 2nd stack to the initial stack/VC
Edit - When I set my storyboard as follows (with the segue from VC to VC) the view transitions, then the VC just goes blank, it doesn't transition back to the login View, but the app is unusable
Read this: ios - Navigation between multiple NavigationControllers
well, Navigation controllers are an entirely different entity.
you cant push onto them.
You should use self.present(UINavigationController(), animated: true, completion: nil)
I have UIPageViewController with 3 UIViewControllers ("FirstVC", "SecondVC", "ThirdVC").
ViewControllers changes by scroll, but I need to change its by click on UIButtons.
How I can do this?
Maybe some func, in which VC will setup by StoryboardID?
Thanks for all answers!
You can easily programmatically navigate through the pages of a UIPageViewController using:
setViewControllers([targetPage], direction: .forward, animated: true, completion: nil)
In the case where you have a UIPageViewController embedded in a ContainerView, and you want buttons in the "root" view to control the page view controller, the basic process is:
add navigation methods (funcs) to your page view controller class
save a reference to the page view controller when it is loaded have
your buttons call the navigation funcs using that reference
When your "root" view controllers loads and instantiates the view controller that is embedded in your ContainerView, it calls prepare(for segue:...) - which is where you get your reference.
In Storyboard, where you embed your view controller in the ContainerView, you will see a standard "segue" connection. In the Attributes Inspector, give that segue an Identifier, such as "PageControllerEmbedSegue".
In your root controller class, add a class-level var:
var myPageVC: BasicPageViewController?
and in prepare():
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// get a reference to the embedded PageViewController on load
if let vc = segue.destination as? BasicPageViewController,
segue.identifier == "PageControllerEmbedSegue" {
self.myPageVC = vc
}
}
Now, you can call functions / get properties of your embedded view controller.
I have a full example on GitHub: https://github.com/DonMag/EmbeddedPageView
There are a couple ways. You could add a segue in the Storyboard file and call
performSegue(withIdentifier: "toResponseTime", sender: self)
otherwise you could do something like.
let controller = self.storyboard!.instantiateViewController(withIdentifier: "AngelDetailViewController") as! AngelDetailViewController
self.navigationController!.pushViewController(controller, animated: true)
I have two view controllers and a Navigation contoller in a storyboard. In the first view controller I have two buttons.
Both buttons segue to the second view which contains a map and opens the map with different info. They are both of the kind show.
The first button when clicked opens the map with the navigation bar at the top (it loads from the side).
The second button loads the map without the navigation bar (it loads from the bottom).
I want both buttons to load the map with the navigation bar.
I am using xcode 7.3 swift and storyboards
Also using prepare for segue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "lav"){
let DestViewController = segue.destinationViewController as! MapView
DestViewController.type = typeLav
}
if(segue.identifier == "cam"){
let DestViewController = segue.destinationViewController as! MapView
DestViewController.type = typeCam
}
}
Set the segue action
Present Modally
Show Up from bottom, and without navigation controller, so there is no navbar too.
Push
Push the view controller to current navigation stack, so the navigation bar is shown
btw, method prepareForSegue was used to setup data transfered between view controllers;