Presenting ViewController on Tabbar Item - swift

I have a tabbar with 3 items. When I click on the second Item on the Tab, I want to present another tabbar which would be like a presentation and maybe the rootViewcontroller but I am unable to do that because it appears like a normal controller above the main tabbar.
I have extended UITabBarControllerDelegate
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
if let controller = self.viewControllers?[self.selectedIndex] as? BaseVC {
controller.modalPresentationStyle = .fullScreen
self.present(controller, animated: true, completion: nil)
}
}
BaseVC is the Tabbar controller I am trying to present.
but this does not change the behavior of the item.

Related

How to set title of navigation item after open another view controller using with present modally - Swift

I have two view controllers in my application. Root view controller has some components and one of them is a button. That button provides to open another view controller using with present function. Second view controller(SelectTimeViewController) that opens when the button is tapped, was opened successfully. I am trying to set navigation title and items but I can not see them.
I did not use storyboard so root view controller is setting from AppDelegate.
let viewController = ViewController()
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = UINavigationController(rootViewController: viewController)
window?.makeKeyAndVisible()
When tapped the button, "openVC" function is invoked.
#IBAction func openVC(_ sender: Any) {
self.navigationController?.present(SelectTimeViewController(), animated: true, completion: nil)
}
I am trying to set title and rightBarButtonItem in SelectTimeViewController's viewDidLoad function but I can not see both of them.
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "close"), style: .plain, target: self, action: #selector(closeIt))
self.navigationItem.title = "Select Time"
}
In additional to this, I can see both title and right bar button item when change the "openVC" function like as bellow.
#IBAction func openVC(_ sender: Any) {
self.navigationController?.pushViewController(vc, animated: true)
}
You have to push the SelectTimeViewController instead of present
Or if you really want to present it, you should present another UINavigationController that has the rootViewController as SelectTimeViewController()

Swift - resetting vc in nav controller that is embedded in tab bar

I have a customerViewController that has a simple a form. When the user presses submit, a segue is triggered and another view appears. The problem occurs when the user goes back to the customerViewController and finds all of the old information still there. I could simply reset the form fields, but what I'd really like is to find a way to reset the entire VC. From what I've learned so far, the way to reset a vc that hasn't been pushed is to remove it and then add it back.
customerViewController is the initial view controller in a navigation controller which is embedded in a tab bar controller. I have a tabBarController class that is a UITabBarControllerDelegate. This is where I call:
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
if item.tag == 2 { //This is the tab with my navigation controller
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "CustomerVCID")
var viewcontrollers = self.navigationController?.viewControllers
viewcontrollers?.removeFirst()
viewControllers?.insert(vc, at: 0)
self.navigationController?.setViewControllers(viewcontrollers!, animated: true)
}
The problem with my code is that navigationController?.viewControllers is nil in the code above. I can reference viewControllers which gives me a list of tab bar viewControllers, but I'm not sure how to get from there to the navigation controller.
I guess my question is, assuming that I'm on the right track, how do I reference the view controllers in my navigation controller?
You can reset your form values in vc inside the viewWillAppear(_:),
class ViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
//clear the textfields, textviews values etc. here.
}
}
It turns out, I was over-complicating things by trying to access navigationController.viewControllers or tabBarController.viewControllers. All I needed was viewControllers which is a property of UITabBarController that contains an array of the controllers associated with each tab:
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
if item.tag == 2 { //tab with navigation controller
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vcon = storyboard.instantiateViewController(withIdentifier: "CustomerVCID")
for viewcontroller in viewControllers! {
if let vc = viewcontroller as? UINavigationController {
vc.viewControllers.removeFirst()
vc.viewControllers.insert(vcon, at: 0)
vc.setViewControllers(vc.viewControllers, animated: true)
}
}
}

Swift 5 pop all Controllers before tab switch

I have trouble pop all controllers when i do click on tabor item. I have tabbar Controller created programmatically. What i tried to do is... user next methods:
extension TabbarViewController: UITabBarControllerDelegate{
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
self.navigationController?.popViewController(animated: false)
}
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
self.navigationController?.popViewController(animated: false)
})
}
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
self.navigationController?.popViewController(animated: false)
return true
}
}
AppDelegate Contains
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let rootNavController = UINavigationController(rootViewController: TabbarViewController())
UIApplication.shared.keyWindow?.rootViewController = rootNavController
According to your code, your tab bar controller is the root of a navigation controller, so self.navigationController will refer to that navigation controller. This means that the line:
self.navigationController?.popViewController(animated: false)
will try pop the tab bar controller from the navigation controller, but because it is the root, it does nothing.
I assume you have navigation controllers as each of the tabs of the tab bar controller, and you want to pop those navigation controllers to their roots, right?
You should use the viewController parameter to refer to your desired navigation controllers:
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
(viewController as? UINavigationController)?.popToRootViewController(animated: false)
})
}

Dismiss current navigation controller when clicked tab bar

I have got a tab bar controller and in home view controller i have a navigation controller.
-Tab Bar Controller
-- HomeVC
--- VC1 navigation push -> VC2
In VC1 navigation bar is not hidden but inside VC2 is hidden. And im controlling it with viewwillappear and viewwilldisappear.
override func viewWillAppear(_ animated: Bool) {
navigationController?.navigationBar.barStyle = .blackTranslucent
}
override func viewWillDisappear(_ animated: Bool) {
navigationController?.navigationBar.isHidden = false
}
But turning back to the VC1 without swipe, I mean clicking tab bar homeVC icon hides navigation bar. I want to dismiss or pop current viewcontroller and turn back to VC1.
So you can do this by popToRootViewController of UINavigationController. you have to handle this in tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) method of UITabBarDelegate.
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
if let rootView = self.viewControllers!["Index of VC1 Controller"] as? UINavigationController {
rootView.popToRootViewController(animated: false)
}
}

Why does this UITableViewController dismiss modally?

I have a UITableViewController that, when presented from one screen, is presented with the standard 'show' segue from right to left, and when presented from another screen (a UIViewController), is presented modally from the bottom. I got this to work properly with the help I got from a question I asked a few months ago (has screenshots).
The key was creating the segue from the UINavigationController of my Settings screen to the shared UITableViewController instead of creating it from the UITableViewCell. Strangely though, even though it presents correctly from right to left, dismissing it closes it modally (top to bottom).
I'm making the presenting table view controller a delegate of the UITableViewController it's presenting so it will handle the dismissal. Here's the protocol and extension it implements (Swift 2.3):
protocol DismissalDelegate : class {
func selectionDidFinish(controller: UIViewController)
}
extension DismissalDelegate where Self: UIViewController {
func selectionDidFinish(viewController: UIViewController) {
self.dismissViewControllerAnimated(true, completion: nil)
}
}
And I set it in the segue defined in the presenting controller:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "goToLifts" {
let destination = segue.destinationViewController as! LiftSelectionTableViewController
destination.dismissalDelegate = self
} else {
return
}
}
The presented table view controller calls delegate?.selectionDidFinish(self) when the user makes a selection (in didSelectRowAtIndexPath):
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
guard (dismissalDelegate != nil ) else {
return
}
dismissalDelegate?.selectionDidFinish(self)
}
That calls this method in the presenting table view controller:
func selectionDidFinish(controller: LiftSelectionTableViewController) {
self.dismissViewControllerAnimated(true, completion: nil)
}
I've looked through the APIs for presenting view controllers and haven't been able to find anything that exposes options to control this. The dismiss(animated:completion:) API even says it's for dismissing a view controller presented modally, but I don't see anything else having to do with dismissal.
How can I get this thing to dismiss the same way it's presented when it's presented from my UITableViewController (right to left, and back) but keep the modal behavior when presented from the other view (a UIViewController)?
I'm a little confused here, it looks like you are using the delegate because the presenting view controller should know how LiftSelectionTableViewController got presented.
So in the table view controller, you would have
func selectionDidFinish(viewController: UIViewController) {
self.navigationController?.popViewControllerAnimated(true)
}
In the other view controller, you should have
func selectionDidFinish(viewController: UIViewController) {
self.dismissViewControllerAnimated(true, completion: nil)
}
If I'm wrong and you can't know how the view controller was presented, then I would try checking to see if the top view controller on the navigation controller is presented view controller. Pop the view controller if it is, dismiss the view controller if it isn't.
func selectionDidFinish(viewController: UIViewController) {
if self.navigationController?.topViewController == viewController {
self.navigationController?.popViewControllerAnimated(true)
} else {
self.dismissViewControllerAnimated(true, completion: nil)
}
}