I'm building an app and I've decided to build my user interfaces in multiple Storyboard files. Each Storyboard is a group of similar actions. For example, LogInStoryboard contains views for logging in and for registering a user.
I've run into a bit of problem with navigating to a new Storyboard and dismissing all the previous view controllers to clean up after myself.
This is my dataflow:
1) App launches into a log in view. Root view controller is LogInViewController, which lives in LogInStoryboard.
2) User taps the register button to summon the modal RegistrationViewController, also lives in LogInStoryboard.
3) User completes registration and is automatically signed in.
At this point, the view controller stack is [LogInViewController, RegistrationViewController]. After registering, the user is automatically signed in so I want to navigate to their home screen, HomeViewController. However, HomeViewController lives inside another Storyboard HomeStoryboard.
I want to dismiss both LogInViewController and RegistrationViewController, and then I want to instantiate HomeViewController from HomeStoryboard and present it. This way I have a simple view controller stack and the LogInStoryboard view controllers can all be deallocated.
What would be the best way to achieve this sort of flow? Or should I even be so worried about those old view controllers?
Its very often the case that your login flow acts almost as an entirely separate app who's only function is to authenticate the user and write the user info to your database. In this case when you are done with the login instead of performing a segue what you want to do is replace the entire view hierarchy with HomeViewController. To do this you can simply call UIApplication.shared.keyWindow! = UIStoryboard(name: "HomeStoryboard", bundle: nil).instantiateInitialViewController() (assuming you made HomeViewController the initial view controller). Of course this has no animation and is kind of ugly so you way want to use UIView.transition(with:duration:options:animations:completion:) to animate the change instead. Example:
UIView.transition(with: UIApplication.shared.keyWindow!, duration: 0.25, options: .transitionCrossDissolve,
animations: {
UIApplication.shared.keyWindow!.rootViewController = UIStoryboard(name: "HomeStoryboard", bundle: nil).instantiateInitialViewController()
})
Swift 4.0
I would start with the HomeViewController as the Initial View Controller.
And from there create the LogInViewController.
if shouldLogin {
let storyboard = UIStoryboard(name: "LogInStoryboard", bundle: nil)
let loginVCtrl = storyboard.instantiateViewController(withIdentifier: "yourLogInViewControllerID")
present(loginVCtrl, animated: true)
}
And after your user finished the Login/Registering process you can call:
dismiss(animated: true)
So your ViewController stack looks like:
[HomeViewController]
[HomeViewController, LogInViewController]
[HomeViewController]
set your HomeViewController in appdelegate as navigationcontroller and set navigationcontroller as rootviewcontroller
NOTE: Both actions perform in appdelegate
Related
I would like to open the specific view from the notification widget.
normally other answers are create new view..(let viewcontroller = ... )
so If you continue to call, continue use memory..
So, I want to open viewA, which is already opened in my app, and then move to viewB.
My application structure is basically a viewA when the application is launched.
What I think is that instead of creating a new viewA, I want to move to viewB using the navigation.push from the already existing viewA.
The way to check whether a particular page already exists, how to show that page at the top , and how to navigation.push is work.
now i'm using this code to open viewA from Appdelegate
let MainView: Main_View_List_ = mainStoryboard.instantiateViewController(withIdentifier: "Main_List_View") as! Main_View_List_
let nav = UINavigationontroller.init(rootViewController: MainView)
UIApplication.topViewController()?.present(nav, animated: true, completion: nil)
Assuming you have access to the navigation controller, you'll want to do something like this to pop back to viewA:
for viewController in nav.viewControllers {
if viewController is ViewAClass {
viewController.pushViewBFlag = true
nav.popToViewController(viewController, animated: true)
return
}
}
Once you get back to viewA, you can check for pushViewBFlag and create and push viewB.
Alternately, since it seems that you are setting viewA as the root of your navigation controller, you could do: nav.popToRootViewControllerAnimated(true) to get back to viewA. You would need to then handle pushing viewB from viewA.
I make an app that has 3 tabs. I want to make my tab bar controller dynamically change the view controller of the first tab bar according to the logged in user type. The rest two tab bars are static. For example, if the user type is 1, I want to show ViewController1 for the first tab, and if the user type is 2, I want to show ViewController2 instead. Is this impossible to achieve when the tab bar is designed in the storyboard? I use storyboard in the app.
You can change these by using the function on a tabview controller setviewcontrollers (see documentation here: https://developer.apple.com/documentation/uikit/uitabbarcontroller/1621177-setviewcontrollers).
For instance I have a storyboard with 4 Viewcontrollers in a tabviewcontroller, and then in the first viewController that loads, I added the following in viewDidLoad()"
let storyboard = UIStoryboard(name: "myStoryboard", bundle: nil)
let newTab = storyboard.instantiateViewController(withIdentifier: "testControllerID") as! TestViewController
let myControllers = [newTab, tabButton2, tabButton3, self, tabButton4]
tabBarController?.setViewControllers(myControllers, animated: true)
So I was able to rearrange my previously defined tabs as well as add "newTab", which is a VC designed on the storyboard, given an identifier, but not actually added to the tabViewController.
Hope that helps
I am trying to leave the initial view controller, and go into the blank view controller. That is fine, but that would make the blank view controller also part of the navigation controller, which is not what I want. I want to segue out of the view controller.
In the view controller I try to segue out of, it pops it self, and when I try the method in the view will appear of the target view controller, self.navigationController?.topViewController returns itself, but self.navigationController?.popViewControllerAnimated(animated) doesn't work
If you have a navigationController do
self.navigationController?.popViewControllerAnimated(false)
Otherwise do
self.dismissViewControllerAnimated(false, completion: nil)
Update
Go to your Storyboard, select the ViewController you want to navigate to and add a storyboard id. Make sure the click "Use Storyboard ID"
Go to the class you want to navigate from and add the following code
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// vc is the Storyboard ID that you added
// as! ... Add your ViewController class name that you want to navigate to
let controller = storyboard.instantiateViewControllerWithIdentifier("vc") as! ViewController
self.presentViewController(controller, animated: true, completion: { () -> Void in
})
Add this code in the action that you use when you want to navigate.
I believe this can be done without having to write any code at all. To Segue out of a Navigation Controller follow these steps:
Create a Segue from the View Controller that has a Navigation Controller as it's root view controller to the View Controller that you would like to go to next (without being inside the Navigation Controller)
Click on the new Seque
Open the Attributes Inspector
Choose 'Kind' -> 'Present Modally'
Choose 'Present' -> 'Over Current Context'
In Swift 2, Xcode 7.1
As the image above, TabBarController will be the main view. Anonymous user can go to the home tab, if they click on the "Me" (Profile) tab, I want the app will pop up the new login segue (navigation controller). User need to login 1st before they can go into the "Me" tab.
Currently I have override the TabbarControllerDelegate in the TabBarController class, which as below (I use Parse, so user = PFUser.currentUser(), Parse will cache the user):
func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool {
if (viewController is MeViewController && user == nil) {
print("login \(viewController)")
// How could I go to the Login Segue from here?
return false
} else {
return true
}
}
How could I achieve my goal from here? Or any better advice? Btw, I am not able to use performSegueWithIdentifier with the TabBarController class unless I use it within the ProfileViewController class (UIViewController) to achieve it. But if I did that, the app will display the view in 'Me' Tab first then go to the 'Login' segue, which is not what I wanted
It will be great thanks for any advices
If you want the user to not be able to go to me before login, you can just do a check with a static bolean which will be initialize in app delegate.
Then if the bolean is set to false (default value), you can invoke the your login popup.
No point here to perform a segue, just put an identifier on the view in the storyboard (identity inspector => storyboard id) and then you can invoke this particular view of the storyboard like this :
let SB = UIStoryboard(name: "MyStoryboard", bundle: nil)
let controller = SB.instantiateViewControllerWithIdentifier("MyId")
self.presentViewController(controller, animated: true, completion: nil)
Segues are only for views which are linked to each other, i personnaly almost never used them.
I recommend that you make the login UINavigationController segue come directly from the UITabBarController instead of on the "Me" controller. This is because you can't modally present your login controller through the "Me" controller if its not on the screen.
Give the segue an identifier (eg. "my-identifier"):
Click on the segue in the storyboard editor and fill in the identifier field in the right sidebar.
After this is configured correctly, the following code will perform the login segue (note the use of tabBarController since you should have the segue configured from the UITabBarController:
tabBarController.performSegueWithIdentifier("my-identifier", sender: self)
I have MainViewController, which contains buttons(onclick pushViewController).
In inner page i write:
let vc = MainViewController(nibName: "View", bundle: nil);
self.navigationController?.presentViewController(vc, animated: true, completion: nil)
Buttons do not work after returning to MainViewController (onlick nothing happens)
ok. Issue here is with navigation.
1) You are opening second view with Push
2) You are again opening main view but with present
Issues:
1) Presented view controller must have navigation controller in order to do Push.
2) Why you want to present main view again. You can directly use popToRootView method to go back on main view.