As shown in the photo below, I have a TabBar controller as my root view controller with some navigation controller attached to it. In my VC1 and VC2, I have the tab bar and navigation bar on screen which is what I want, However, for VC3, I do not want tab bar. Currenty I am just hiding and unhiding the tabbar at view will appear. However, this presented some poor user interface. What I think would be great is when I present VC3, it just present "over" the current screen whilst keeping the navigation bar. Is it possible to do that? I'd also like the presentation to be from right to left just like a segue (As oppose to show from bottom)
Note. I use performSegueWithIdentifier for going to VC3
I have seen some solution where I have to set the rootVC to be a normal view controller instead (A login VC in my case) . However, I am trying to avoid that because If the user has already logged in, I do not need to present the login. If I have that as my rootVC all the time, the user will be forced to load and "see" the login VC first before seeing the tabBarVC. This will cause. Unless there is a way to get away with it?
FIRST WAY : PUSH
You can hide bottom bar on push by enabling the flag of VC3 from storyboard.
Please refer following picture:
SECOND WAY : PRESENT
Set a navigation controller for VC3 and present that navigation controller from VC1 or VC2 or TabBar as shown in following image :
You can create a new window, then present your VC3 on it, this would ensure it's over tabbar, in exchange of making new navigation controller and fake back button. But I'd rather check the hide tabbar on push option in storyboard, it give the tabbar hiding a nice animation
For your second question, the best way is make the rootVC in storyboard the tabbar controller, and separate the loginVC, in AppDelegate, check for user login or not and set the rootVC to loginVC or tabbar controller
When first time you login, you have to set the root view controller as login view controller.Then in viedDidLoad method you have to set check already logged in or not.When first run your app it has not logged in so you can go login page.Once you logged in you can go to next page directly.You can use LoginViewController viewDidLoad method.
- (void)viewDidLoad
{
[super viewDidLoad];
BOOL loggedIn = [[NSUserDefaults standardUserDefaults] boolForKey:#"logged_in"];
if(loggedIn)
{
NSLog(#"It has already logged in so go to next view");
}
}
When you login successfully set the bool to YES
- (IBAction)actionLoggin:(id)sender
{
if ([strUsername isEqualToString:#"xxxxxx"] && [strPassword isEqualToString:#"xxxxxx"]) //If it is correct
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"logged_in"];
}
}
Then when you log out,set the bool to NO
- (IBAction)actionLoggin:(id)sender
{
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"logged_in"];
}
1>For tab bar you can delete Tabbar or you can Hide Tabbar from storyboard but don't take separate nav controller for VC3.
You can kept navbar item title value of VC3 as VC2 or VC1 navbar title while pushing or presenting VC3.For that you have to user performseguewithidentifier and initialise VC3 nabber item title value
2> Hey for user is already login then in appdelgate you can change root view controller.By finding user is logged in or not from user default.
you can change rootviewcontroller using window.rootviewcontroller and while doing log out you again can change rootviewcontroller.
Related
I'm new to iOS and trying to build one AR app with navigation bar, I defined 3 viewcontroller in the app, and using storyboard and navigation bar to switch the viewcontrollers:
VC1 - Home view, there is one button navigated to VC2;
VC2 - this view controller will call camera to scan image marker; when the image was identified, I just instantiate VC3 programmatically.
VC3 - just showing some information for the image, I added 2 buttons here which will navigated to VC1 and VC2 seperately.
So VC1->VC2, VC2->VC1 are OK as the navigation bar configuration, the problem is when I click button in VC3 to VC1 or VC2, both navigation bar in VC1 and VC2 disappear. It seems I missed some configuration here, can anyone tell me how to make the navitation bar always there?
You can check navigationBar's visibility in method viewDidAppear of VC1 and VC2 like this:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(#"navigationBar is hidden:%#\n",
self.navigationController.navigationBar.hidden ? #"YES": #"NO");
}
It should be YES in VC1 and VC2, you probably change navigationBar's visibility in somewhere, find it then fix it.
I have solved my problem from below link, it is working perfectly
Change destination of Navigation Back button
When presenting or dismissing VC, I do not want to keep hiding and showing tabBar because it creates a poor user experience. Instead, I want present the next VC straight over the tab bar such that when I dismiss the nextVC by dragging slowly from left to right, I can see the tabBar hidden behind the view (As shown in image below)
Note, my app has two tabs with two VCs(VCA,VCB) associated to it. Both VC also have navigation bar embedded. VCA segues to VCA1 and VCB segues to VCB1. At the moment, inside VCA and VCB I am calling the following function to segue with some hiding and unhiding done when viewWillappear (Code below).
self.navigationController?.showViewController(vc, sender: self)
// Inside ViewWillAppear Only reappear the tab bar if we successfully enter Discover VC (To prevent drag back half way causing tab bar to cause comment entry to be floating). This code check if we have successfully enters DiscoverVC
if let tc = transitionCoordinator() {
if tc.initiallyInteractive() == true {
tc.notifyWhenInteractionEndsUsingBlock({(context: UIViewControllerTransitionCoordinatorContext) -> Void in
if context.isCancelled() {
// do nothing!
}
else {
// not cancelled, do it
self.tabbarController.tabBar.hidden = false
}
})
} else {
// not interactive, do it
self.tabbarController.tabBar.hidden = false
}
} else {
// not interactive, do it
self.tabbarController.tabBar.hidden = false
}
----------Working solution from GOKUL-----------
Gokul's answer is close to spot on. I have played with his solution and came up with the following improvement to eliminate the need to have a redundant VC and also eliminate the initial VC being shown for a brief second before tabVC appears. But without Gokul, I would never ever come up with this!!
Additionally, Gokul's method would create a bug for me because even though I do have a initial "normal" VC as LoginVC before tabVC is shown. This loginVC is ONLY the rootVC if the user needs to login. So by setting the rootVC to tabVC in most cases, the navVC will never be registered.
The solution is to embed navigation controller and tabBar controller to one VC. But it ONLY works if the navVC is before the TabBarVC. I am not sure why but the only way that allowed me to have navVC-> tabVC-> VC1/VC2 is to embed VC1 with a navVC first than click on VC1 again to embed tabVC (It wouldn't allow me to insert one before tabVC and I also had to click the VC1 again after embedding the NavVC).
For your requirement we need to make some small changes in your given view hierarchy
Let me explain step by step,
To meet your requirement we have to add a UIViewController(let's say InitialVC) embedded with a UINavigationController and make it as initial viewcontroller.
Then add a UITabbarController with 2 VC (VCA,VCB) // IMPORTANT: Without any navigationcontroller embedded.
Add a segue between InitalVC and TabbarController with an unique identifier(ex: Initial)
In viewWillAppear of InitalVC perform segue as below (InitialVC is unnecessary to our design we are using this just to bridge navigationController and tabbarController).
self.performSegueWithIdentifier("Initial", sender: nil)
In TabbarControllerclass hide your back button, this ensures that InitialVC is unreachable.
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.hidesBackButton = true
}
Now add a segue from a button between VCA and VCA1, thats it build and run you will see VCA1 presenting over VCA's tabbar.
What we have changed?
Instead of adding UINavigationController inside UITabbarController we have done vice versa. We can't directly add Tabbar inside navigation to do that we are using InitialVC between them.
Result:
1st way is create a image of the tabbar using UIGraphicsGetImageFromCurrentImageContext and set it on the bottom of the other view...
2nd way is show the next view in another new window that is above the tabbar, that way you wont need to hide the tabbar anymore, but seems like its in the navigation controller so this way doesnt seems available
Hiding and unhiding the tab bar is unnecessary. You only need to embed the UITabBarController inside the UINavigationController. That is, UINavigationController as the initial vc, UITabBarController as the root vc of UINavigationController.
In my image, my first Tabbar is HomeViewController and the second Tabbar is CameraViewController.
What is the proper way to segue to the Tabbarcontroller? You can see the read line, I try to segue this but I
always get the back button in my HomeViewController and It display weird like not showing the navigation name.
In CameraViewController I hide the Tabbar for the use camera button. I try to use segue programmatically like this one.
[self performSegueWithIdentifier:#"sample" sender:sender]
but It doesn't work properly. Is this possible to segue to TabbarController?
You can't call
[self performSegueWithIdentifier:#"sample" sender:sender]
Because you're in TabBarController already. You could implement custom flow. By pressing "Back" button - just show TabBar and change selected tabBarItem for example…
update
used this
[self.tabBarController setSelectedIndex:0];
I have a login screen as my root view controller. If the user is already logged in, I want to skip over the login screen and show the main view controller.
The code below does that, but it shows a back button in the nav bar instead of the default nav bar.
Is there a way to remove the back button? There is a menu button that is supposed to be there, so simply hiding the back button will not suffice.
Thanks!
- (void)viewDidLoad {
if(GetUserName != nil){
[self pushingView:YES];
}
[super viewDidLoad];
}
-(void)pushingView:(BOOL)animation{
MainViewController *revealViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"RevealViewController"];
[self.navigationController pushViewController:revealViewController animated:animation];
}
Don't try to remove the back button, instead remove the need for the back button. Instead of using pushViewController:animated: use setViewControllers:animated:. In this way you only have one view controller on the stack (and you save the memory of keeping the view controller in existence).
Ideally you wouldn't even load the login view controller and then you'd save even more memory and time.
I have storyboard of several view controllers embedded in Navigation Controller.
Due to navigation logic in later views of storyboard, the back button (in the left upper corner, in navigation bar) does not go back to the first view. I am wondering where and how to change this behaviour of Back button of second view only. Appreciate any ideas, examples.
Of course you could implement a custom back button. But there is also a nice way to keep using the default button.
Simply check if the current viewController is still in the navigation stack in viewWillDisappear before you call super.viewWillDisappear(). If it is not, the back button has been pressed. Then you can do the popToRootViewControllerAnimated.
override func viewWillDisappear(animated: Bool) {
if (navigationController?.viewControllers)!.contains(self) {
// back button was pressed
self.navigationController?.popToRootViewControllerAnimated(animated)
}
super.viewWillDisappear(animated)
}
The custom back button appears to be the best solution. The code inside your action method would look like the following in swift:
self.navigationController?.popToRootViewControllerAnimated(true)
//Just change the true to false if you don't want it animated.
I hope this helps (if you had not already found the answer). Cheers!
If you meant to say: Prevent Back Button Navigating to Previous Controller and move to first view controller:
You could do this by creating a custom back button - drag a button in storyboard to the top left of the navigation bar, and wire it up to your view controller. In your custom back button's selector write:
[self.navigationController popToRootViewControllerAnimated:YES]
Assuming you have a view controllers stack like : VC1 > VC2 > VC3, and you want to back to VC1 when tapping back on VC3, then you could set this code in VC2 :
[self.navigationItem setBackBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:#"Back" style:(UIBarButtonItemStylePlain) target:self action:#selector(backToVC1)]];
Then, always in VC2 :
- (void)backToVC1
{
[self.navigationController popToRootViewControllerAnimated:YES];
}