Presenting Modal ViewController from (Table)ViewController inside a NavigationController inside a TabBarController - ios

When I try presenting the modal controller right from the table view controller (could be a normal view controller as well), it appears behind the tab bar and looks quite ugly as I'm using a blur effect on it. I am using a navigation controller because I need to have a bar at the top and, after research, found that's the best way to do it.
I have found that doing something like:
self.parent?.parent?.present(ModelViewController(), animated: true, completion: nil)
when wanting to present the modal controller works. However, I imagine this isn't very safe. What is the correct way of doing this?

In order for the ModalViewController to present in front of the tab bar, its modalPresentationStyle has to be set to overFullScreen. So for instance when initializing the ModalViewController:
self.modalPresentationStyle = .overFullScreen (Swift 3 syntax)

Related

Transition from one modal VC to another without delay swift

I have a basic scenario:
I present a VC modally using self.present(, animated:, completion:).
Sometimes due to interactions in this modal VC i need to close one modal and open another one.
So i do the following:
weak var presenter = self.presentingViewController
let newVc = UIViewController()
presenter?.dismiss(animated: true, completion: {
presenter?.present(newVc, animated: true, completion: nil)
})
This works but there is the annoying delay when switching the VC's when user sees the original presenter and can try to interact with it (to open other modals...).
I tried setting animated: false but that doesn't seem to work :/
I can't really switch to UINavigationController model for this because the modals i am presenting themselves are Page View Controllers and have the whole hierarchy of dependent views; the user is never going 'back'; so i'd really like to just present the new modal as quickly as possible...
Update My question is not about how to control or choose the animation. My questions is about having no delay between the modals.
The built-in view controller architecture that switches views with no transition is the tab bar controller. So just turn your view controller into a tab bar controller — with no visible tab bar! To change to the other view controller just change tabs (in code). The change is instant.
This screencast makes it clear that this works as described. We present a view controller (yellow). Then we switch back and forth between two view controllers (green and yellow) as the presented view controllers, instantly. Finally, we dismiss whichever one (green or yellow) is showing. I'm doing it all with simple buttons but that's just for the demo; obviously you could do this however you like. It's the architecture that's the important thing.
I can think only of solutions which would require you to handle the animations yourself
create custom modal transition using UIViewControllerTransitionCoordinator
add your controllers to container views as suggested by #muhammed-gül
present newVC over self and dismiss all presented controllers when you're done
And just a tip, you don't always need to wait for the dismiss completion closure, you can call this and it usually works, but still the underlying viewController is visible.
dismiss(animated: true)
present(newVC, animated: true)

Can't add view infront of modal controller's view

I have a modally presented view controller and I want to push a modal view on top of it. This should be simple to do, but I've missed something :)
The modally presented view controller doesn't cover the whole screen (it uses custom presentation) so I can't just add my view on top of that. But when I try to add my view to either the presenting view controller, or just onto UIApplication.shared.keyWindow.rootViewController.view I get a very strange result.
I've tried this using the default modal presentation an it still behaves in the same way, so I don't believe it's my custom presentation causing this.
Here is the exploded view from Xcode - with the overlay at the correct position front and center.
And here is the simulator at the time this interface was snapshotted.
Does anyone know why the alert view (which is clearly at the top of the stack looking in Xcode) doesn't appear?
NB: I'm pretty confident that the exploded view in Xcode is correct because it matches up with the output from po [[[[[UIApplication sharedApplication] keyWindow] rootViewController] view] recursiveDescription]
I think you should try to present some vc in your current and in other view controllers first.
... // your view controller
present(/* your alert view controller */, animated: true, completion: nil)
For example, it should show a empty vc like below. See if you can present any vc normally. If yes, it might be your alert view controller problem.
... // your view controller
let vc = UIViewController()
present(vc, animated: true, completion: nil)
... // presented a black screen, it works

Dismissing modally presented ViewController always throws me back to root

I've had this issue for months with multiple views, both Apple provided like ImagePicker and VCs from storyboard.
I believe that it has something to do with the underlying views we have both a tab bar controller and navigation controller in most views.
Strange thing is using some open source views from pods does not cause this bug.
So I'm two views deep on a navigation controller and present another view modally on top with present(vc, animated: true, completion: {})
Works like a charm, now dismissing that view with dismiss(animated: true, completion: nil) throws me back all the way to the initial view or root view of the navigation controller, had both happen before, depending on the presented view.
Update:
Build a sample project trying to reproduce the behavior but failed. Drew a reduced diagram to better explain the current bug behavior.
Also noticed that if I'm invoking the post view one step earlier in the Fandom view it works as expected.
In my case i am using UITabBarController, and I wrote code in viewWillAppear of UITabBarController
self.selectedIndex = 2
so when i present any thing from any controller whose parent is UITabBarController and when i dismiss that it automatically open third tab of UITabBarController.
Maybe you explicitly wrote any code to select specific index of TabBar.
Maybe this is useful for you or anyone else.

How can I present a modal view on top of a tab bar controller?

I made one button on the navigation bar. I made it to modal view. But the problem is I can't bring this modal view on the top of the tab bar. What should I do?
In addition, I have used storyboard's segue to present the modal view.
Enter to see storyboard image
Enter to see simulator image
It's hard to tell from the screenshots, but it seems like what you want is for the tab bar to become greyed out just like the background of the view inside the UITabBarController?
Where are you presenting the modal view from? If view controller A is inside your tab bar controller, then presenting the modal view from A will result in the tab bar not getting grayed out. If you present from the tab bar controller, it should do what you want.
In the presenting view controller's code, instead of
present(modalViewController, animated: true, completion: completion)
try using
tabBarController?.present(modalViewController, animated: true, completion: completion)
(Where modalViewController and completion are whatever you mean to use for these arguments, of course.)
If you are using a segue to present the modal controller, then the same concept applies. Move the segue to the tab bar controller and then perform it on the tab bar controller from the presenting view controller.
tabBarController?.performSegue(withIdentifier: "yourSegueIdentifier", sender: tabBarController)
You can simply use the modalPresentationStyle of your view controller and set it to fullScreen or overFullScreen and this will automatically hide the tab bar, whether the view controller is presented from the tab bar or not.
Swift 4 example:
presentedVC.modalPresentationStyle = .overFullScreen
You can check the documentation for more information: UIModalPresentationStyle

Display extra view controller without removing the tab bar

My app has a menu and a UITabBarController. What I want to do is to display a view controller that belongs to my menu but not to the UITabBarController, However I don't want to remove the UITabBarController. I tried codes similar to the one below but they are removing the UITabBarController.
tabBarViewController.selectedViewController?.presentViewController(ExtraViewController, animated: true, completion: nil)
You should get UINavigationController of selected ViewController and then push view you want to present. Otherwise you are presenting modal view controller with presentViewController witch hides your UITabBarController view.
Im not at my computer right now, and cant post any code, but hope this helps.
Best way to do it is to use UINavigationController. You can create new one programmatically and put your menu controller as root.
And if you put this UINavigationController as one of views in UITabBarController then you can preform a code like:
[self.navigationController pushViewController:ExtraViewController animated:NO];
Also you can use storyboard to create your controllers hierarchy like that:
To do that select your menu controller and go to Xcode menu>Editor>Embed in>Navigation Controller and then Xcode menu>Editor>Embed in>Tab Bar Controller.

Resources