Covering a VIewController With another ViewController (NO animation or Transition) - ios

this question may asked before but i can't find any related question thats why posting a new one
so i have 3 tabs and in tab3 i have user profile Tab
in tab3 i wanna show loginViewController (if user haven't logged in yet) else i want to show the default profile tab
i can pass a segue using performSegue or present a view controller like this :
let loginPageView = self.storyboard?.instantiateViewController(withIdentifier: "LoginVC") as! SignupViewController
self.present(loginPageView, animated: true, completion: nil)
but i dont want that ,
i wanna show a different VC at the place of Default VC if user haven't logged in yet without any animation or transition
e.g.
producthunt's iOS app
if user's didn't logged in
and if he did logged in:
see the first image they are not presenting it as pop over or modal.
it seems like they do it on a same VIewController but i'm not sure. anybody can guide me here ?

replacing current Viewcontroller with desired ViewController did the job
let loginPageView = self.storyboard?.instantiateViewController(withIdentifier: "LoginVC") as! SignupViewController
var VCs = self.navigationController?.viewControllers
VCs?.removeLast() // here i removed the current VC
VCs?.append(loginPageView) after that added the desired VC
self.navigationController?.setViewControllers(VCs!, animated: false) // here i'm setting the viewcontrollers with any animation.

Related

What is different between this when we navigate one view controller to another

What is the difference between this first call:
let next = self.storyboard?.instantiateViewController(withIdentifier: "AFVC") as! AddFileViewController
self.present(next, animated: true, completion: nil)
and this second:
let dashboard = self.storyboard?.instantiateViewController(withIdentifier: "DBVC") as! DashboardViewController
self.navigationController?.pushViewController(dashboard, animated: true)
The first usage will present the new view controller. This presentation normally slides the new controller up from the bottom. If you want to go back, you need to create a button or something similar to dismiss it.
The second usage will use the navigation controller to display (via push which normally slides in from the right) the new view controller. You will automatically get a "< Back" button in the navigation bar. But this will only work if the calling view controller is already embedded in a navigation controller, otherwise self.navigationController is nil.

back to initial view controller

As you can see i have an initial view controller with label in it "Initial ViewController". In this view controller i use below code to go to selected tab of Tab Bar Controller
let vc1 = sb.instantiateViewController(withIdentifier: "tabbar") as! UITabBarController
vc1.selectedIndex = selected
let controllers = [vc1]
navigationController!.setViewControllers(controllers, animated: true)
In my First View, there's a button "Present VC" which presents "Presented View".
let vc1 = sb.instantiateViewController(withIdentifier: "PresentedVC") as! PresentedVC
present(vc1, animated: true, completion: nil)
Now i want to go back from presented vc to root vc(Initial View Controller). I can do this with:
let viewController = self.storyboard?.instantiateViewController(withIdentifier: "FirstNavigationController") as! FirstNavigationController
UIApplication.shared.keyWindow?.rootViewController = viewController
but this instantiate Initial View Controller every time and views remain in memory. How can i go back to Initial View Controller without instantiating it?
PS: FirstNavigationController is initial Navigation Controller.
At the very beginning you remove the initial view controller by doing this:
navigationController!.setViewControllers(controllers, animated: true)
All the previous viewControllers are gone now and replaced with the tabbar controller and its children.
If you want to go back to the initial controller, you will have to push the tabbar onto the stack instead of replacing everything with it. E.g.
navigationController?.pushViewController(tabbarVc, animated: true)
First when you did this
navigationController!.setViewControllers(controllers, animated: true)
the initial VC is deallocated (if it has not a strong references)
to keep it you can use push , pop instead of setViewControllers but note it may cause memory issues if you have heavy processing in your app as it will remain in navigationController stack
You are missing the concept between "Presenting" or "Setting" View Controller & "Navigating" the View Controller. You will get the answer, once you understood the concept. Here, it is..
When you are setting the ViewController, you are completely replacing the stack container to the new view controller. the way you did it here:
navigationController!.setViewControllers(controllers, animated: true)
In this case, STACK holds the addresses of the latest set/presented ViewControllers that means previous whole ViewController vanished.
On the other hand, if you are navigating to other view controller by pushing it. you can go back to previous controller by simple popping the ViewController address from stack. or to next ViewController by pushing
e.g:
self.navigationController?.pushViewController(tabbarVc, animated: true)
self.navigationController?.popViewController(animated: true)
Summary:
If you push TabBarController then, only you will get InitialVC.
Now, in your case, you are setting the ViewController and hence, you are not getting InivtialVC. Try Pushing tabbarVC This will work.
navigationController?.pushViewController(tabbarVc, animated: true)

Swift How to present Tabbar on Button click

In my project i want to present Tabbar on button click, now i have already created tabbar and i give identity name as "tabbar" that i show you in below image
so now i am using below code to call Tab bar controller but i am not getting it.
let tabbar: UITabBarController? = (storyboard.instantiateViewController(withIdentifier: "tabbar") as? UITabBarController)
navigationController?.pushViewController(tabbar, animated: true)
can you guys suggest me what i need to do and which code is useful to me to present Tabbar controller.
For more specification : i added below image in which there is blue button in one viewController i want to present tab bar controller on click of that blue button
Thank you.
Try this and see:
Using Storyboard Segue: Connect your segue as present modally with your action button.
Programatically: Use self of view controller (UIViewController) and present it modally, like this.
if let tabbar = (storyboard.instantiateViewController(withIdentifier: "tabbar") as? UITabBarController) {
self.present(tabbar, animated: true, completion: nil)
}
Here is result:
Use this, you dont have the Navigation controller over there, thats why it won't push that way, instead, you need to use following code:
self.present(tabbar, animated: true, completion: nil)
You should be aware that Apple's HIG (Human Interface Guidelines) say that if you have a tabbed application that should be the root-level navigation for the entire app. you're not supposed to do what you are trying to do from a human interface perspective.
That said, it should be technically possible.
My guess is that you don't have a navigation controller.
Use the debugger to check the value of self.navigationController, or add a print statement:
let tabbar: UITabBarController? = (storyboard.instantiateViewController(withIdentifier: "tabbar") as? UITabBarController)
print("navigationController = \(navigationController)")
print("tabbar = \(tabbar)")
navigationController?.pushViewController(tabbar, animated: true)
If either navigationController or tabbar displays as nil, that's your problem.
Select the viewController from which the button click triggered and Select Editor form xcode menu->Embed In->NavigationController.
then write this in button action
let tabbar: UITabBarController? = (self.storyboard?.instantiateViewController(withIdentifier: "tabbar") as? UITabBarController)
self.navigationController?.pushViewController(tabbar!, animated: true)
According to your images I think that your tabBarController has no back button. Means user cannot go back.
If that is the case you can do this.
let tabBar = self.storyboard?.instantiateViewController(withIdentifier: "tabBar")
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = tabBar

Log out and clear VCs below current VC

We are looking to change the way a user logs out of our app. In order to do that, we want to dismiss all the VCs below the current VC and put another VC on top as the root VC. Right now we are doing this which I believe does not dismiss any VC below from memory.
let viewController = storyboard?.instantiateViewController(withIdentifier: "SignIn")
if let unwrappedViewController = viewController {
self.present(unwrappedViewController, animated: true, completion: {})
}
The problem is that the VC that we want to put on top is not embedded in a Navigation Controller or tab bar controller. How would we dismiss the VCs and set the new VC as the main VC as if the user was opening the app for the first time without having previously logged in? We also do want the transition to be animated with whatever animation is normal for that event (modal animation is fine). I have read a bunch of different ways on doing it but I want to know which way is best practice and should be implemented specifically dismissing all VCs and putting a new VC that isn't in a Nav controller on top.
If you can access the UIWindow of the app, you can set its rootViewController property to your sign-in view controller, effectively removing all current view controllers and adding the sign-in view controller instead. Here's an example:
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
// Should remove all subsequent view controllers from memory.
appDelegate.window?.rootViewController.dismiss(animated: true, completion: nil)
// Set the root view controller to a new instance of the sign in view controller.
appDelegate.window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SignIn")

How to transit from the last view in a tab to the last view of another tab

This is the diagram of my project:
The logic flow I want to achieve:
1: The user enter all the requested information of a task through all the views in the first tab and finally reach to the last view named "writeTask". Here the user is supposed to tap "confirm" button.
2: Upton tapping "confirm" I want to navigate the user to the second view(named "newTask") of the second tab which shows the very task the user just entered. The user can go to "myTasks" table view by tapping button on the top left corner.
My first approach:
Upon tapping the button, I instantiateViewController "myTasks" and do self.present(myTasks, animated: true, completion: nil). But now the user will go to "myTasks" table view first without going straight to "newTask". I tried to solved this by perform a segue in its viewDidload by self.performSegue(withIdentifier: "showTaskDetails", sender: self)
Issue: the segue is performed too late (after the view is load and the user will see the "myTasks" view for half second).
Second approach:
I create a modal segue between the tap button and the "newTask" view. And I create an unwind segue between "newTask" view and "myTasks" table view. So the user will be navigated to "newTask" view, they can go back to "myTasks" through the unwind segue.
Issue: during the unwind segue the "wirteTasks" view will be displayed for a short moment before "myTasks" table view is displayed.
This is the new approach I have come up with:
let mainStoryboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let vc: UITabBarController = mainStoryboard.instantiateViewController(withIdentifier: "tabBarController") as! UITabBarController
let nvc = vc.viewControllers?[1] as! UINavigationController
let destinationVC = nvc.viewControllers[0] as! myTasksTableViewController
destinationVC.task = task
vc.selectedIndex = 1
self.present(vc, animated: true, completion: nil)

Resources