I am developing the iOS app. and it has some design restrictions by the client. So it looks like I have to use navigation controller and the tab controller simultaneously on different number of Viewcontrollers.
I can categories my views into 2 category.
SignUp/Login views (this is entry point at first start of app)
MainView -> This become entry point once the user is login
Now Category 1 is using NavigationView Controllers. where as Category2 is using Tab bar controllers.
What I want case 1: I want when the user install my app, he is taken to Login view which has Navigation View. Now if he already has no account he will go to "Create new account" this is the 2nd scene of the Navigation view. Now on successful creation of account, he needs to close all other navigation view controllers and need to jump to MainView which will be Tabbar view controller.
case 2: suppose user close my app after getting login, when he open it up again, now the entery point will be Mainview which has Tab bar view controller. Now I know I need to do it in App delegate method but how?
I am doing this way,and it looks like working. But I am not getting bottom tab. Why is it so?
class ViewSwitcher {
static func updateRootViewController() {
let status = UserDefaults.standard.bool(forKey: KeyConstants.IS_USER_LOGGEDIN)
var rootViewController : UIViewController?
#if DEBUG
print(status)
#endif
if (status == true) {
let mainStoryBoard = UIStoryboard(name: "Main", bundle: nil)
let mainTabBarController = mainStoryBoard.instantiateViewController(withIdentifier: "idTab1VC") as! Tab1VC
rootViewController = mainTabBarController
} else {
let mainStoryBoard = UIStoryboard(name: "Main", bundle: nil)
let signInViewController = mainStoryBoard.instantiateViewController(withIdentifier: "idLoginVC") as! LoginVC
rootViewController = signInViewController
}
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = rootViewController
}
}
Any Idea how to do these cases? How to navigate programmatically by closing all the view controllers trees?
The same process I have been using for my app.
Use this code to change the rootViewController in Case2
var window: UIWindow?
var tabBarController : UITabBarController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Tabbar controller
let storyBoard = UIStoryboard.init(name: "Main", bundle: Bundle.main)
let tab1 = UINavigationController.init(rootViewController: storyBoard.instantiateViewController(withIdentifier: "tab1"))
tab1 = UITabBarItem.init(title: "Title 1", image: UIImage(named : "Image.png") , tag: 0)
let tab2 = UINavigationController.init(rootViewController: storyBoard.instantiateViewController(withIdentifier: "tab2"))
tab2 = UITabBarItem.init(title: "Title 2", image: UIImage(named : "Image.png") , tag: 1)
// Navigation controller or Login view controller
let nav1 = UINavigationController.init(rootViewController: storyBoard.instantiateViewController(withIdentifier: "nav1"))
tabBarController = UITabBarController.init()
tabBarController?.delegate = self
tabBarController?.selectedIndex = 0
tabBarController?.viewControllers = [tab1,tab2]
// The Bool value which you have to set as True after a user logged in
if UserDefaults.standard.bool(forKey: "LoggedIn"){
print("Tabbar")
self.window?.rootViewController = self.tabBarController
}else{
print("Navigation")
self.window?.rootViewController = nav1
}
return true
}
Before or After that, you have to write the same code where a user clicked on login in your loginViewController, in your case it is Case1
func loginClicked(){
UserDefaults.standard.set(true, forKey: "LoggedIn")
DispatchQueue.main.async {
let appdelegate = UIApplication.shared.delegate as! AppDelegate
// Same as above code and replace self with appDelegate without if condition and at last
appdelegate.window?.rootViewController = appdelegate.tabBarController
}
}
And after user logged out
DispatchQueue.main.async {
UserDefaults.standard.set(false, forKey: "LoggedIn")
let appdelegate = UIApplication.shared.delegate as! AppDelegate
let story = UIStoryboard.init(name: "Main", bundle: Bundle.main)
let nav1 = UINavigationController.init(rootViewController: storyBoard.instantiateViewController(withIdentifier: "nav1"))
appdelegate.window?.rootViewController = companyNavigation
}
Use below code in app delegate didFinishWithLaunchingOptions , for main view directly.. here uid means stored value whether to check user is Active or Not.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let user_id = UserDefaults.standard.value(forKey: "uid")
{
let homeViewController = storyboard.instantiateViewController(withIdentifier: "HomeTabBarCtrlr") as! UITabBarController
let nav = UINavigationController(rootViewController: homeViewController)
self.window!.rootViewController = nav
}else{
SignUp/Login views
}
Step by step approach to this would be:
Check if user is logged in or not. For this use UserDefaults.
If user not logged in, set LoginVC as rootVC.
On Login save a key in UserDefault to signify user logged in.
Next time when user opens the app check for key and if user logged in, set TabBarVC as rootViewController.
At Logout, clear the key.
Sample Code for the above will be:
AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
{
...........
//Check for user login and set rootViewController.
if UserDefaults.standard.bool(forKey: "login"){
self.window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()
}
else{
self.window?.rootViewController = UIStoryboard(name: "Login", bundle: nil).instantiateInitialViewController()
}
return true
}
At Login Success
func loginUser(){
...
if userLoginSuccess{
UserDefaults.standard.set(true, forKey: "login")
}
}
At Logout
UserDefaults.standard.set(false, forKey: "login")
As like you know that you want to do it in Appdelgate.
When user login successfully you have to store a flag in userdefault.
In app delegate you have to check that if this flag is set or not.If set then create a navigation view controller with your initial view controller call moveToLoginWindow().
or if not then create tab bar view controller call movetoTabBarController().
func moveToLoginWindow() -> Void {
if let rootController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LoginVC") as? LoginVC{
let navigationController = UINavigationController.init(rootViewController: rootController)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
}
}
func movetoTabBarController() -> Void {
let nav2 = UINavigationController()
let second = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "secondViewController") as? SecureNotesVC
nav2.viewControllers = [second!]
nav2.tabBarItem = UITabBarItem.init(title: "Titel 2", image: UIImage.init(named: "2.png"), selectedImage: UIImage.init(named: "2_sel.png"))
let nav3 = UINavigationController()
let third = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "thirdviewController") as? FormFillsVC
nav3.viewControllers = [third!]
nav3.tabBarItem = UITabBarItem.init(title: "Titel 2", image: UIImage.init(named: "3.png"), selectedImage: UIImage.init(named: "3_sel.png"))
let nav4 = UINavigationController()
let fourth = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "fourthviewContoller") as? SettingsVC
nav4.viewControllers = [fourth!]
nav4.tabBarItem = UITabBarItem.init(title: "4", image: UIImage.init(named: "4.png"), selectedImage: UIImage.init(named: "4_sel.png"))
if #available(iOS 11.0, *) {
nav2.navigationBar.prefersLargeTitles = true
nav3.navigationBar.prefersLargeTitles = true
nav4.navigationBar.prefersLargeTitles = true
}
let tabBarController = UITabBarController()
tabBarController.viewControllers = [ nav2,nav3, nav4,nav5]
self.window!.rootViewController = tabBarController;
}
Related
so i have this storyboard and i want the user to be shown the login view controller if he is not logged in or the tab view controller otherwise.
this is my code inside the app delegate :
`
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
UITabBar.appearance().tintColor = .white
// check user
let authListener = Auth.auth().addStateDidChangeListener { auth, user in
if user != nil {
print("USER IS NOT NIL")
userService.observeUserProfile(uid: user!.uid) { userProfile in
userService.currentUserProfile = userProfile
}
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "TabBarVC") as! UITabBarController
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = vc
self.window?.makeKeyAndVisible()
} else {
print("USER IS NIL")
userService.currentUserProfile = nil
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "FirstVC") as! UIViewController
vc.modalPresentationStyle = .fullScreen
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = vc
self.window?.makeKeyAndVisible()
}
}
}
`
My problem is that if the user is not logged it looks like this:
As you can see the view is not full screen even though i specified that in the app delegate so the user can simply dismiss it and enter the main screen. Also in the tab view controller i have the main screen with a playing video and the login screen also has a playing video in the background and both videos are played at the same time XD .Any tips would be welcome.
change storyboard--> viewcontroller---> attribute inspector---> change presentation from Automatic to Full Screen
let nav = UINavigationController()
nav.navigationBar.isHidden = true
//your Controller
let first = Router.shared.splashVC()
let third = Router.shared.CustomTabbarVC()
third.selectedIndex = 0
//add multiple controller in array
nav.viewControllers = [first,third]
UIApplication.shared.keyWindow?.rootViewController = nav
UIApplication.shared.keyWindow?.makeKeyAndVisible()
First Select all ViewController and change presentation mode Automatic from Full Screen in Simulated Metrics.
Added UINavigationController in rootViewController
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "TabBarVC") as! UITabBarController
let navigationController = UINavigationController(rootViewController: vc)
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = navigationController
vc.navigationController?.isNavigationBarHidden = true
self.window?.makeKeyAndVisible()
I am using SWRevealViewController for side menu functionality. Its working fine but whenever I have added the following code in didFinishLaunchingWithOptions method. side menu is not working for first time launch.
How to solve this problem??
this is my Code :
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// UserDefaults.standard.synchronize()
// IQKeyboardManager.sharedManager().enable = true
self.window = UIWindow(frame: UIScreen.main.bounds)
guard UserDefaults.standard.object(forKey: "IsFirstTime") != nil else {
UserDefaults.standard.set(true, forKey: "IsFirstTime")
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "LaunchViewController") as! LaunchViewController
let navigationController = UINavigationController.init(rootViewController: viewController)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
return true
}
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "SWRevealViewController") as! SWRevealViewController
// let navigationController = UINavigationController.init(rootViewController: viewController)
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()
return true
}
Thank you
Here you are making LaunchViewController initial VC on first launch. That's why it is not working at first time.
To use SWRevealViewController you need two view controller, one is front view controller which you want to show first time and second is for drawer which maybe tableViewController that contains all other view controller. To add SWRevealViewController call openDrawer() in AppDelegate.
func openDrawer() {
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let drawerVC = storyboard.instantiateViewController(withIdentifier: "idDrawerVC") as! RearVC
let dashboardVC = storyboard.instantiateViewController(withIdentifier: "idFrontVC") as! FrontVC
let frontNavigationController = UINavigationController(rootViewController: dashboardVC)
let revealViewController = SWRevealViewController(rearViewController: drawerVC, frontViewController: frontNavigationController)
revealViewController?.delegate = self
revealViewController?.view.backgroundColor = .clear
revealViewController?.modalTransitionStyle = .crossDissolve
window?.rootViewController = revealViewController
}
I have two VC (ViewController, SettingsVC, VC2).
How can I make it so that when you turn on the Switch(located in SettingsVC) when the application starts it would be shown VC2??
The default is ViewController.
Write this code in didFinishLaunchingWithOptions -
let isSwitchOn = UserDefaults.standard.bool(forKey: "isSwitchOn")
if isSwitchOn {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc2 = storyboard.instantiateViewController(withIdentifier: "Your identifier")
self.window!.rootViewController = vc2;
}
Set isSwitchOn in SettingsVC like this -
UserDefaults.standard.set(true, forKey: "isSwitchOn")
I guess it can be duplicated, but I looking everywhere and didn't find a solution for me.
So about my question. I have something like this
open this image to see more
In my AppDelegate I have func
func logIn() {
let userExist = UserDefaults.standard.string(forKey: "auth_key_user")
if userExist != nil && userExist != "" {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let whereToGo = storyboard.instantiateViewController(withIdentifier: "AllPostsOfUserTabBarController") as! AllPostsOfUserTabBarController
window?.rootViewController = whereToGo
}
}
If user exist it lead me to first view controller inside tab bar controller. There I have navigation button with action to logout.
I need log out(send data to the server) and then go to my first view controller with text field and button where I can again log in.
How do I need to implement it?
Try this code after logout-
DispatchQueue.main.sync() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginVC = storyboard.instantiateInitialViewController()
appDelegate.window?.rootViewController = loginVC
}
Hope it helps!
Put this code in function of your logout button. It will throw you back to your root controller.
func logoutBtnClicked()
{
DispatchQueue.main.sync()
{
(send your data to server)
self.navigationController?.popToRootViewController(animated: true)
}
}
Try this in appdelegate
While Login
self.window?.rootViewController = whereToGo
While Logout
func setupLoginViewController() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginVC: UIViewController? = storyboard.instantiateViewController(withIdentifier: "loginVCID") as? UIViewController
let navController: UINavigationController? = UINavigationController(rootViewController: loginVC!) as UINavigationController
window?.rootViewController = navController
}
I was wondering what is the best practice to implement login screen for Master-Detail application which has SplitView Controller as a root controller. I am using the appDelegate to display the login screen if the user is not logged in. However, when I want to dismiss the loginVC the app goes into blank Detail page instead of the MasterController. Would be a modal login screen better option for Master-Detail app?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginVC = storyboard.instantiateViewControllerWithIdentifier("LoginVC") as! loginViewController
self.window?.rootViewController = loginVC
return true
let splitViewController = self.window!.rootViewController as! UISplitViewController
let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController
navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem()
splitViewController.delegate = self
return true
And then in my loginVC:
#IBAction func goHome(sender: AnyObject) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let splitViewController = storyboard.instantiateViewControllerWithIdentifier("SplitViewControllerID") as! UISplitViewController
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window?.rootViewController = splitViewController
}
By changing the code of goHome function it works for me. Below is the code:
#IBAction func goHome(sender: AnyObject) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let splitViewController = storyboard.instantiateViewController(withIdentifier: "SplitViewControllerID") as! UISplitViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = splitViewController
splitViewController.preferredDisplayMode = .allVisible
let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController
navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
}