How to maintain the navigation with a segue "present modally"? - swift

I have : navigation controller -> tableViewController -> tab bar Controller -> ViewController1 / ViewController2 / ViewController3
I click on a cell on the TableViewController and I open the TabBar. All is OK
But, I wanted to have more details from the datas in the TableViewController so I decided to make a popup with the content of the cell. I found this tutorial https://www.youtube.com/watch?v=S5i8n_bqblE => GREAT ! It's about the use of segue "present modally" with a viewcontroller containing the popup. I made a link from the popup to the tabBarController and I lose the Navigation Bar
I tried to play with navigationBar but nothing is working. I changed the type of segue but I don't obtain what I want.
I think the problem come from the type of segue. It's OK if I use it like a go/back in viewController. Do you have any solution about using this sort of popup or do I have to use another way ?
Thanks

Ok, let's take a look.
Navigation Bar is a view which is provided by Navigation Controller. Sometimes we are confused with navigation bars and navigation items. Navigation bar is the only one and it belongs to navigation controller, navigation item belongs to individual view controller from navigation stack. So, first step is simple: if you want navigation bar, wrap your modally presented controller into navigation stack.
Yes, you will face other problem, the blurred view of previous controller will become a black area. Why? there is special object called Presentation Controller (UIPresentationController) which is responsible for how controller will be presented. And it hides view of previous controller by default (in sake of performance, I think).
Ok, let's move. We can create custom presentation controller and tell it not to hide view of previous controller. Like this:
class CustomPresentationController: UIPresentationController {
override var shouldRemovePresentersView: Bool {
return false
}
}
Next step. In controller we want present modally we have to specify to things: we want to use custom presentation controller and we also want to adjust delegate object for transitioning (where we can specify custom presentation controller). The trick is that you have to do it inside initialiser, because viewDidLoad is too late: controller had been already initialised:
class PopupViewController: UIViewController {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
modalPresentationStyle = .custom
transitioningDelegate = self
}
}
Final step. When PopupViewController became delegate for its own transitioning, it means this controller is responsible for all of them. In our particular case popup controller provides custom version of presentation controller. Like this:
extension PopupViewController: UIViewControllerTransitioningDelegate {
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return CustomPresentationController(presentedViewController: presented, presenting: presenting)
}
}
That's all. Now you should see view of previous controller.

Related

Is there a way to call a function once a View Controller leaves the view stack?

ViewDidDisapear and ViewWillDisappear are still called if another View Controller is above the (say, for example, you push a view controller on top of it). Is there a function that is only called once the view controller is removed from the navigation stack? Adding a function to the back button works, but what if the user decides to to the edge pan gesture to dismiss the view? Is there an action that accounts for both events?
Yes, I can think of few ways to do this off the top of my head
One option would be to add some code to a dealloc method of the UIViewController.
If you don't expect the view controller controller to get deallocated when it leaves the stack you can also set a UINavigationControllerDelegate for the UINavigationController and define
func navigationController(_ navigationController: UINavigationController,
didShow viewController: UIViewController,
animated: Bool) {
guard let poppedViewController =
navigationController.transitionCoordinator?.viewController(forKey: .from)
<Do something with the popped VC>

How to get the navigation bar to show large title upon a segue back?

I have a tab bar app where one of the views is a UITableViewController containing static cells as content with 1 section and 1 row.
I want the Large Title to be set to "Always," so I made the selection on the storyboard and the title was large on the simulator. Now when the user taps "Start Chat," the app will segue to the Virtual Assistant View Controller, where the Large Title is set to "Never" on the storyboard. Now the problem is that when the user segues back to the previous view controller with the "Start Chat" table view cell, the title is not large anymore.
It is interesting that when I set the table view to be scrollable, the title becomes large again upon dragging down the table view. I made sure the navigation bar on the Navigation Controller storyboard is checked with the "Prefers Large Titles." I am using Xcode 11, and this was not a problem when using Xcode 10.
I tried creating a custom class for the view with the start chat button and this code did not work in making the title large from a segue back:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationItem.largeTitleDisplayMode = .always
navigationController?.navigationBar.prefersLargeTitles = true
What else could I do? Any help will be greatly appreciated!
I'd use willMove(toParent:) to change the title back before the segue is performed.
override func willMove(toParent parent: UIViewController?) {
navigationController?.navigationItem.largeTitleDisplayMode = .always
navigationController?.navigationBar.prefersLargeTitles = true
}
Set the properties when setting up the UINavigationController, before presenting it. If you already presented the navigation controller, try doing this to force-update the navigation bar:
navigationController?.navigationItem.prompt = ""
navigationController?.navigationItem.prompt = nil
I took this workaround from this question.
In your particular case, it would be better to subclass the navigation controller and set those properties in its viewDidLoad method, so its properties (largeTitleDisplayMode and prefersLargeTitles) are set in a self-contained code.

View controller won't push

I have a function inside my app delegate which is supposed to push a View Controller when called from a Siri Shortcut.
func pushNewView() {
if let wind = UIApplication.shared.delegate?.window {
if let rootViewController = wind?.rootViewController {
let viewToPush = TripTableViewController()
if let alreadySomeOneThere = rootViewController.presentedViewController {
alreadySomeOneThere.navigationController?.pushViewController(viewToPush, animated: true)
} else {
rootViewController.navigationController?.pushViewController(viewToPush, animated: true)
}
}
}
}
When I called pushNewView() from my AppDelegate, nothing happens.
If I present the view controller instead of pushing it, that does work but I want the view controller pushed.
I'm not using any storyboards, all my code is programmatic.
Does anyone know how to make this function successfully push the View Controller?
Nothing is happening because neither alreadySomeOneThere nor rootViewController are embedded in a navigation controller.
In order to push another view controller, there needs to be an existing navigation controller in place.
You need to do one of two things. Either redo your setup such that alreadySomeOneThere and rootViewController are embedded in a navigation controller, or you need to present the new view controller from alreadySomeOneThere or rootViewController.
Please note that you can't push a navigation controller. If you choose to put alreadySomeOneThere and rootViewController in a navigation controller, then just push viewToPush. Don't create another navigation controller.
If you instead decide to present the new view controller from alreadySomeOneThere or rootViewController, then depending on the needs of viewToPush, you may or may not need viewToPush embedded its own navigation controller.

Unwind doesn't work and I have the correct code

I have this segue in a navigation view controller. This has a ViewController called SectionsTableViewController, and this has a bar button item that I linked to exit action and called "close" action segue.
And in my ViewController I have this cose:
class ViewController: UITableViewController {
#IBAction func close(segue: UIStoryboardSegue) {
print("Hey")
}
}
But it doesn't work.
The unwind segue code needs to be in the view controller you're unwinding back to, as opposed to the one with the Stop button. So if your view controllers normally move in this direction:
StartingViewController -> SectionsTableViewController
you want to put the unwind segue in StartingViewController.
Putting the unwind in the wrong view controller and not connecting it via Interface Builder are the only possible ways this can go wrong.
Did you hook up the method to the object in the storyboard (control + drag to Exit)?

NavigationBar not showing on TableviewController in swift

I have a CollectionView running in my project and the collectionViewController connected to another tableview using custom segue as follows.
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
selectedMenuItem = indexPath.row
//Present new view controller
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main",bundle: nil)
var destViewController : UINavigationController
switch (indexPath.row) {
case 0:
destViewController = mainStoryboard.instantiateViewControllerWithIdentifier("NewTableView") as UINavigationController
break
default:
destViewController = mainStoryboard.instantiateViewControllerWithIdentifier("NewTableView") as UINavigationController
break
}
self.presentViewController(destViewController, animated: true, completion: nil)
}
above code populating my NewTableview successfully but the tableview missing navigation bar completely.
so far my tries as follow...
i embedded new navigationController to collectionView results remain unchanged.
i embedded new navigationController to NewTableView results remain unchanged.
i tried unwind segue method using custom navigation button action method.so i insert the navigation bar item and button to the view and Method works,but it works strangly when navigation bar button pressed it takes me to my main collection view controller thats what i what.but i have another back button appears in collection view rowindex item name on it.when i pressed the button it take me back to the NewTableView its like looping through.
i don't know what i am missing (any delegate method).and i noticed the newTableView data loading from the bottom with animation...
i wondering is there any way to put a navigation programmatically with back button behaviour...
Thanks in Advance.....
You'll have to instantiate the navigation controller, not the actual view controller from your storyboard. So instead of instantiating NewTableView (the view controller you want embedded in the navigation controller), you should add an identifier to your UINavigationController so that it will be instantiated instead of the view controller itself.
Just imagine that you reuse the NewTableView controller which does not require a navigation controller as its root, how would iOS be aware of that ? So add an identifier to your hosting UINavigationController and instantiate that. The navigation controller has a root dependency on the rootViewController which will be shown by default, so you only need to display the UINavigationController and the NewTableView controller will be shown based on the dependency it has with the navigation controller.