Present a View modally from a tab bar controller - ios

How can I present a View modally from a tab bar controller so that the view goes over the actual one?
I want to build a view with a camera. Something just like "WhatsApp" or "Instagram" where there is a button in the middle that the user can click and the camera view shows up.
Additionally, the user should move the tab he was before when the close button was clicked.
This is how my ViewController is connected to the TabBarController:

I've had to implement something similar in an app I'm currently building, it's relatively straightforward to do, you need to implement a delegate method of UITabBarController in order to achieve this.
The delegate method you need to implement is:
tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool
Returning false from this method will stop the tab controller from selecting your tab, you then just need to implement your own logic to present the UIViewController programatically.
Here's an example:
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
// If your view controller is emedded in a UINavigationController you will need to check if it's a UINavigationController and check that the root view controller is your desired controller (or subclass the navigation controller)
if viewController is YourViewControllerClass {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let controller = storyboard.instantiateViewController(withIdentifier: "storyboardID") as? YourViewControllerClass {
controller.modalPresentationStyle = .fullScreen
self.present(controller, animated: true, completion: nil)
}
return false
}
// Tells the tab bar to select other view controller as normal
return true
}
I've not tested the above code as my implementation is slightly different and has more variables. The general principle is the same.
Let me know how you get on and I'll update the answer if necessary.

Assuming that you are conforming to UITabBarControllerDelegate, you could implement:
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
// here, you should edit "0" to be matched with your selected item
// for instance, if there is 5 items and the desired item is in the middle, the compared value should be "2"
if tabBarController.selectedIndex == 0 {
// simply, you will need to get the desired view controller and persent it:
let desiredStoryboard = UIStoryboard(name: "Main", bundle: nil)
let desiredViewController = desiredStoryboard.instantiateViewController(withIdentifier: "storyboard id")
present(desiredViewController, animated: true, completion: nil)
}
}

let modalVC = self.storyboard?.instantiateViewController(withIdentifier: "ViewControllerIdentifier")
modalVC.modalTransitionStyle = .crossDissolve
modalVC.modalPresentationStyle = .full or .overfullscreen // please check which of the options work
self.present(modalVC, animated: true, completion: {
})

Related

Programatically load a navigationController on tabitem click

I have made a UITabBarController where when selecting one of the item I load an imagepicker.Now after user chose an image from picker i want to load a navigation controller, which I'm not able to. My code is
extension BaseTabBarController : UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if self.viewControllers?.index(of:viewController) == 2 {
// Presenting image picker here
present(self.imagePicker, animated: true, completion: nil)
return false
} else {
return true
}
}
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
}
}
here's the code after user has picked image
extension BaseTabBarController : ImagePickerDelegate {
func doneButtonDidPress(_ imagePicker: ImagePickerController, images: [UIImage]) {
//This is the StoryboardID of Navigationcontroller i want to goto
let detailVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "UploadNavigationController")
//This is not working
present(detailVC, animated: true,completion: nil)
}
}
Here controller is not shown and I get this warning
Warning: Attempt to present <UINavigationController: 0x7fb4969c4800> on <BaseTabBarController: 0x7fb49780ea00> whose view is not in the window hierarchy!
I want to show the navigation controller with the tab bar still visible in the bottom
I guess, as you want to show the navigation controller with the tab bar still visible in the bottom, then you should first dismiss image picker then push new controller not present.
Because if you present any controller will cover whole screen as it is presenting from root controller. If you push then it will push from current controller and tabor remains as it was.
extension BaseTabBarController : ImagePickerDelegate {
func doneButtonDidPress(_ imagePicker: ImagePickerController, images: [UIImage]) {
self.imagePicker.dismiss(animated: true) {
//This is the StoryboardID of Navigationcontroller i want to goto
let detailVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "UploadNavigationController")
//This is not working
let nav = UINavigationController(rootViewController: detailVC)
navigationController?.pushViewController(nav, animated: true)
//present(detailVC, animated: true,completion: nil)
}
}

How to PopUp or Modally Present View Controller from Tab Bar Controller?

How can I create a popup that appears when a button on a Tab Bar is pressed? I would like something similar to this: https://www.youtube.com/watch?v=zDWSaItF2ko.
I have tried many solutions but none have worked.
For example, I have tried this with my main view controller:
This still doesn't work though. How would I go about creating this. I know that I need to present the view controller modally and over current context, but how would I do that from a tab bar controller.
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if viewController is PopupViewController {
if let popupView = tabBarController.storyboard?.instantiateInitialViewController() {
popupView.modalPresentationStyle = .fullScreen
tabBarController.present(popupView, animated: true, completion: nil)
return false
}
}
return true
}
Here are some pictures that may help:
Main Storyboard:
Popup Storyboard:
View Controller Code:
Have you tried debug this using breakpoints in Xcode? From what I can see, the first thing you do is to check whether the view controller that should be selected is of class PopupViewController. Are you sure the view controller is being instantiated correctly?
And by the way I would recommend another way of instantiating the view controller from storyboard rather then:
tabBarController.storyboard?.instantiateInitialViewController()
The first thing is to head over to the storyboard file itself and in the view controller you are trying to instantiate change the Storyboard ID to something for example the class of the storyboard (PopupViewController in your case).
Next you will want to try to instantiate the storyboard itself using the init(name: String, bundle storyboardBundleOrNil: Bundle?) initialiser:
let storyboard = UIStoryboard(name: "Popup", bundle: nil)
And now instantiate the view controller using the storyboard variable like so:
let popupViewController = storyboard.instantiateViewController(withIdentifier: "PopupViewController") as! PopupViewController
Finally you can give it some extra configuration and present it on the tab bar controller:
popupViewController.modalPresentationStyle = .fullScreen
tabBarController.present(popupViewController, animated: true)
Edit
Addionally to make it more Swifty, I recommend guard statement for early exit. Finally the method could look something like this:
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
guard viewController is PopupViewController else { return true }
let storyboard = UIStoryboard(name: "Popup", bundle: nil)
let popupViewController = storyboard.instantiateViewController(withIdentifier: "PopupViewController") as! PopupViewController
popupViewController.modalPresentationStyle = .fullScreen
tabBarController.present(popupViewController, animated: true, completion: nil)
return false
}

Present View Controller embedded in Navigation Controller apart of Tab bar controller modally

I have a view controller embedded inside of a navigation controller. This navigation controller is the third item inside of my tab bar controller. I want to present the view controller modally.
This is what I've tried, but it does not run
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
// CameraView is the Storyboard ID of the VC I want to present
if viewController is EditPreviewVideosViewController {
if let newVC = tabBarController.storyboard?.instantiateViewController(withIdentifier: "CameraView") {
// None of this prints
print()
print("new vc is allowed")
print()
tabBarController.navigationController?.present(newVC, animated: true, completion: {
print("complete")
})
return false
}
}
return true
}
Get the right navigation controller from tabbarController childs
if let nav = tabBarController.viewControllers[tabBarController.selectedIndex] as UINavigationController {
nav.present(newVC, animated: true, completion: {
print("complete")
})
}
You are finding view controller in wrong storyboard
with this line
let newVC = tabBarController.storyboard?.instantiateViewController(withIdentifier: ....
It should be
let newVC = UIStoryboard.init(name: "NameOfYourStoryboardContainsVideo", bundle: nil).instantiateViewController(withIdentifier: "CameraView")
Now your if will execute correctly

ios swift - instantiating same VC from multiple tabs

I have multiple tabs connected via separate navigation controllers. I want to to instantiate same End Pt VC, irrespective of which tab user chooses tabs 1 through 4.
When I select Tab 1 it shows End Pt VC because it is connected via Segue. However when I select other tabs I manually try to push EndPt VC as shown in the tab controller method. But it shows blank screen. How can I present the same End Pt VC irrespective of tab selection?
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
if let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "EndPointTVC") as? EndPtListTableViewController{
viewController.selectedTab = self.selectedTab
if let navigator = self.navigationController {
navigator.pushViewController(viewController, animated: true)
}
}
}
You can detect when the UITabBarController changes tab via its delegate UITabBarControllerDelegate. In the following delegate method, you can cast the selected view controller to a UINavigationController (which is what I can make out in the screenshot you attached).
extension MyTabBarController: UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
let myVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "MyViewControllerStoryID") as! MyViewController
let navController = viewController as! UINavigationController
navController.viewControllers = [myVC]
print(viewController)
}
}
Now, no matter which tab you choose, a new MyViewController instance is created. Even hitting the same tab multiple times will replace the current instance for a new MyViewController instance.
Try to instantiate the viewcontroller from the storyboard and then present it. Also, make sure that you have given the target viewcontroller the storyboard Id "EndPointTVC" in the Identify section.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier : "EndPointTVC")
viewController.selectedTab = self.selectedTab
self.present(viewController, animated: true)

Instantiate ViewController when using Storyboard

I am using Storyboard and want to push a view controller for display in UITabBarController at the click of tab bar item.
For this, I am using an existing ViewController linked to TabBarController created on Storyboard and using below code. However, I get exception, Storyboard doesn't contain a view controller with identifier 'SwitchViewController'
func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool {
let switchViewController = self.storyboard?.instantiateViewControllerWithIdentifier("SwitchViewController")
self.presentViewController(switchViewController, animated: true, completion: nil)
return false
}
UPDATE: I added Storyboard ID for SwitchViewController in Main.storyboard and commented the above code. App Failed with same error when I moved to this tab
I am using iOS 8 and Xcode 7. Kindly help
Check your Storyboard ID,
Try this one,
func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool {
if viewController is SwitchViewController {
let switchViewController = self.storyboard?.instantiateViewControllerWithIdentifier("SwitchViewController") as! SwitchViewController
self.presentViewController(switchViewController, animated: true, completion: nil)
return false
}
return true
}
Try the following code:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let VC = storyboard.instantiateViewControllerWithIdentifier("SwitchViewController")

Resources