My iOS application is based on John-Lluch's SWRevealViewController to get sidebar navigation. I have ran into a navigation problem that I don't know how to solve.
I want one of the menu items to lead to a page that doesn't contain a sidebar but a back button instead. (The other menu items leads to pages where the sidebar can be opened).
To get a back button on a view I need to use a Show Detail Segue, but I also need a navigation controller "somewhere" for the back button to show up. (I don't mean that I need a navigation controller AFTER the segue - I have that already - but I need it somewhere before).
Have someone used SWRevealViewController in this way or know how to achieve this? "Where" should I place a navigation controller?
Thanks!
The only working solution I came up with was to use a Category on UIView, that could do my Detail Segues.
#interface UIViewController (SidebarView)
(void)setupSidebarWithGestureRecognizer:(BOOL)useGestureRecognizer;
(void)openSettingsPage;
(void)openAboutPage;
#end
and the .m-file's code for openAboutPage:
/* This method is called by the sidebar. If the sidebar opens the settings page from itself, the back button
* doesn't know where it should point. This method opens the about menu when the sidebar tells it to, and the back button
* is pointing to the home page. */
- (void)openAboutPage {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *about = [storyboard instantiateViewControllerWithIdentifier:#"About"];
[self.revealViewController rightRevealToggleAnimated:YES];
[self.navigationController pushViewController:about animated:NO];
self.navigationController.navigationItem.title = #"About";
}
and the setupSideBarWithGestureRecognizer... method
- (void)setupSidebarWithGestureRecognizer:(BOOL)useGestureRecognizer {
SWRevealViewController *revealViewController = self.revealViewController;
if (revealViewController) {
UIBarButtonItem *sidebarButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"reveal"] landscapeImagePhone:[UIImage imageNamed:#"reveal"] style:UIBarButtonItemStylePlain target:self.revealViewController action:#selector(rightRevealToggle:)];
self.navigationItem.rightBarButtonItem = sidebarButton;
if(useGestureRecognizer) {
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
}
}
}
Then for each page I want to show a sidebar, I just call [self setupSidebar:YES]; in the viewWillAppear method of that view controller.
Related
Note: Problem solved.
Here comes the story. I am using RevealViewController in my project. I am also hiding the navigationBars:
[self.navigationController setNavigationBarHidden];
My project can be seen in the picture below and the "menuButton" is implemented in the tabBarViewController.
Since the navigationBar is hidden due to my interface looks, all tabViews (HomeViewController) will not show the menuButton and the navigationBar as supposed to. I am not using panGestureRecognizer to trigger the menu aswell.
This means I have a problem to trigger the menu via a normal button in HomeViewController. The menuButton-event is placed in tabBarViewController.m:
_menuButton.target = self.revealViewController;
_menuButton.action = #selector(revealToggle:);
So I tried to call a method from HomeViewController to fire the button in tabBarViewController like this:
HomeViewController.m
- (IBAction) onMenuClicked: (id)sender{
tabBar = [[tabBarViewController alloc] init];
[tabBar setupMenu]:
}
tabBarViewController.m
-(void) setupMenu{
[_realMenuButton sendActionForControlEvents:UIControlEventTouchUpInside];
[_realMenuButton addTarget:self.revealViewController action:#selector(revealToggle:) UIControlEventTouchUpInside];
}
In this example I tried to make the realMenuButton and normal UIButton. Ive also tried as a UIBarButtonItem just to trigger the #selector(revealToggle:) But nothing happens in the app when I try to trigger the button from HomeViewController.
Not sure how I shall make this work. Any other Ideas or tricks? Please be specific if so! Regards
Yes, it will still work.
SWRevealViewController is just a subclass of a UIViewController, so you can use it at any point in the app:
By calling presentViewController:animated at some point.
By using it in a navigation stack etc.
Note that you can add gestures from SWRevealViewController to its content view controllers, which will alter the behaviour of used in a navigation view controller, but that's to be expected, and you still have full control over its behaviour.
Edit
The UI structure of your app is still not clear to me - it looks like you're trying to call revealToggle on an instance of SWRevealViewController when the VC in view is infact HomeViewController? How would this work, when SWVC is not even in view?
My best guess is that your UI structure should be as follows:
TabBarController --->(root)UINavigationController --->(root)SWRevealViewController.
Then, on your SWRevealViewController, set HomeViewController as the front view controller, and the TableViewController as the right or left view controller.
Do you mean like this?
it is possible. you can set the menu button in your tabBarController.m, like this :
UIBarButtonItem *menu = [[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:#"menu.png"] style:UIBarButtonItemStylePlain target:revealController action:#selector(revealToggle:)];
self.navigationItem.leftBarButtonItem = menu;
self.delegate = self;
For me, my initial view controller is the login screen (obviously I don't need reveal any VC here...). then when user tap the login button,
UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:yourRootVC];
LeftMenuViewController *leftMenuVC = [[LeftMenuViewController alloc]init];
SWRevealViewController *revealController = [[SWRevealViewController alloc]initWithRearViewController:leftMenuVC frontViewController:nav];
revealController.delegate = self;
[self presentViewController:revealController animated:YES completion:nil];
I've tried it and it should work as normal. Even it isn't initial view controller
In my iOS Project, there is a login ViewController that sends the user to a TabViewController if he has the right credentials.
This TabViewController has 5 tabs, the fifth one is for Logout, which send the user back to the Login ViewController, and of course clears out the already filled credentials of the user.
My problem is that i have the menu of the TableView shown in my Login page.
How to i get rid of this menu in my Login ViewController page ?
I use Xcode6 & Objective-C
if you need any further explanations/source code of my problem, feel free to ask.
note:
In the beginning, I mean when the Login ViewController is first shown to the user, the menu doesn't show.
It turns out that whole UI architecture of your app is based on the UITabBarController. However it is not very good practice in your case. I would like to suggest you add separate modal controller for presenting login page.
Try:
self.tabBar.hidden = YES;
Assuming that you are using a storybaord I have the given solution
I created a sample application and tried replicating your issue, so here's the look at my storyboard
The way i designed it i have a separate login view controller and two view controller (Menu List and Logout) which are embedded in a tabbar controller.
If you're new to storyboard then embedding viewControllers with tabbarController is pretty much straight forward, you select the view controller first and then go to the editors menu in Xcode
Alright now coming back to business, code which i added on the IBAction of the login screen button is given below where MainTabbar is the storyboardID of the TabMaster controller
AppDelegate *appdel = [UIApplication sharedApplication].delegate;
UIStoryboard *storyBoard = appdel.window.rootViewController.storyboard;
TabMasterController *tabController = [storyBoard instantiateViewControllerWithIdentifier:
#"MainTabbar"];
[appdel.window setRootViewController:tabController];
When i executed the application everything was OK and I was able to see the tabbar items after I hit the action button on login screen
Now its time to write some code for the logout tabbar item, so I selected the view controller assigned to the Main tabbar controller and added the delegate mentod of UITabbarController which looks some what like this
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
// Since i have two tabbar items 1 generally means logout in my case
if (tabBarController.selectedIndex ==1) {
AppDelegate *appdel = [UIApplication sharedApplication].delegate;
UIStoryboard *storyBoard = appdel.window.rootViewController.storyboard;
ViewController *tabController = [storyBoard instantiateViewControllerWithIdentifier:
#"LoginVC"];
[appdel.window setRootViewController:tabController];
}
}
LoginVC is the storyboardID of the Login View controller
After adding the above code when i used to tap on the logout tabbar item I was able to go back to the login screen in my storyboard.
Hope that helps.
Either you can add tab bar item programmatically or you can add in storyboard
If programmatically then add like
self.tabBarController.viewControllers = [NSArray arrayWithObjects:
[[UINavigationController alloc] initWithRootViewController:self.myContactsController],
[[UINavigationController alloc] initWithRootViewController:self.searchController],
[[UINavigationController alloc] initWithRootViewController:self.registrationController],
[[UINavigationController alloc] initWithRootViewController:self.loginController], nil];
Set tabbarController as initial view controller in storyboard
After checking login credential, On success
// to get list of current tab bar items
NSMutableArray *tbViewControllers = [NSMutableArray arrayWithArray:[self.tabBarController viewControllers]];
// to remove tab bar items using index value
[tbViewControllers removeObjectAtIndex:3];
[tbViewControllers removeObjectAtIndex:2];
// to add tab bar items
[tbViewControllers addObject:[[UINavigationController alloc] initWithRootViewController:self.myProfileController]];
[tbViewControllers addObject:[[UINavigationController alloc] initWithRootViewController:self.logoutController]];
// to set pre selected tab bar item
self.tabBarController.selectedIndex=2;
// set array items in tab bar
[self.tabBarController setViewControllers:tbViewControllers];
Fixed it, it's not the optimal solution but it worked for me:
what I did is :
1- I deleted the Tab Bar Item from my Login ViewController
2- I inserted a logout button in my table view screens
3- I added segues from my Table view screens to the login screen in my storyboard.
This way if the user clicks on the logout button , he will be directed to the login screen & cannot go back where he was unless he enters his credentials.
This question already has an answer here:
presentViewController does not show Tab Bar or Navigation Bar
(1 answer)
Closed 7 years ago.
I am using following code to launch a view controller modally. This view controller is not being created from scratch. Rather, I created and styled it in storyboard, gave it a name, embedded it in a navigation controller so it has a navigation bar and created cancel and done buttons, gave it a title and the code below launches it.
The problem is that while most of the features of the screen show up such as labels and images, the title and navigation bar that you can see in the storyboard disappear. Has anyone come across this issue and have a fix for it?
My code to launch VC created in storyboard.
- (void) editView:(id) sender
{
NSLog(#"launch button pressed");
UIStoryboard *storyBoard = self.storyboard;
IDEditVC *editVC =
[storyBoard instantiateViewControllerWithIdentifier:#"editvc"];
editVC.item = _item;
[self presentModalViewController:editVC animated:YES];
}
I think what's happening is that since you are directly instantiating the view controller by name it's getting just that from the storyboard rather than embedding it in the nav controller.
Try this:
In your storyboard, make the Navigation Controller the initial/root View Controller for the storyboard
Instead of instantiating by name, use UIStoryboard's instantiateInitialViewController method.
EDIT:
Based on your comments below, you might want to try this:
- (void) editView:(id) sender
{
NSLog(#"launch button pressed");
UIStoryboard *storyBoard = self.storyboard;
IDEditVC *editVC =
[storyBoard instantiateViewControllerWithIdentifier:#"editvc"];
editVC.item = _item;
UINavigationController *nav = [UINavigationController alloc] initWithRootViewController: IDEditVC];
// Do whatever setup you want to here for your title bar, etc
[self presentModalViewController:nav animated:YES];
}
Try to use PushViewController instead of instantiate:
How to push viewcontroller ( view controller )?
Good luck
To give some context, I have logic that programmatically decides what view controller to insert into the navigation controller. For example:
If(true){
MyViewController * MyObject = [[MyViewController alloc]init];
myNavigationController = [[UINavigationController alloc]initWithViewController:MyObject];
else {
MyOtherViewController * MyOtherObject = [[MyViewController alloc]init];
myNavigationController = [[UINavigationController alloc]initWithViewController:MyOtherObject];
}
self.tabBarController.viewControllers=[NSArray arrayWithObjects:myNavigationController,nil];
Hopefully that illustrates my point of how I insert views inside of navigation controller. Now onto my problem:
I have an action listener with a button inside of "MyViewController" that essentially replaces the navigation/tab bar index when the user clicks the button. Is it possible to update a navigation/tab bar index with just a button?
MyViewController.m
- (IBAction)MyActionListener:(id)sender {
MyOtherViewController *MyOtherObject = [[MyOtherViewController alloc] initWithNibName:#"MyOtherViewController" bundle:nil];
[self.view insertSubview:MyOtherViewController.view atIndex:2];
}
When I do this, I get a crash EXEC_BAD_ACCESS I'm just wondering if my implementation/approach is wrong. I noticed this question: Update UITabBar Views?
However, doesn't seem to fit the results I am looking for. Hopefully I am clear. Thanks!
Yes it is possible to switch your views on button click with navigation.
You currently in VC1 , you have other two vc VC2 & VC3 and on button click you choose VC2 or VC3 but you did not change the VC1 place.
I have an UITabBarController that has 3 buttons. The second button points to ViewController1 which is connected to another view called ViewController2. After I tap a button in ViewController2 I programmatically present ViewController1 again, that works perfect except one thing. After I "arrived" to ViewController1 the tab bar disappears.
I'm using this method to navigate back to ViewController1. (exactly I navigate to its navigation controller, but already tried with the view)
- (void)presentViewControllerAnimated:(BOOL)animated {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"storyboard" bundle:nil];
UINavigationController *firstViewNavigationController = [storyboard instantiateViewControllerWithIdentifier:#"destination"];
[self presentViewController:firstViewNavigationController animated:animated completion:nil];
}
I call here the first method
- (void)didTapButton:(id)sender {
UIButton *button = (UIButton *)sender;
CGPoint pointInSuperview = [button.superview convertPoint:button.center toView:self.tableView];
[self presentViewControllerAnimated:YES];
}
This method hides the tab bar in the ViewController2, I already tried without it, therefore there is no problem with it.
-(BOOL)hidesBottomBarWhenPushed
{
return YES;
}
I can't figure out why this thing happens, I think it's a fair solution, that worked well for a several times when I needed to present views. I've read it can happen with segues, but I'm doing it with code without segues.
Actually your code works right. There should not be tab bar when you present FirstViewController from SecondViewController. Because when you call instantiateViewControllerWithIdentifier its basically creates a new instance of that view controller, and of course, there is no tab bar.
The right way to go back to your first view controller is to pop SecondViewController (or dismiss it, if it presented modally). So your final code should be like this
- (void)didTapButton:(id)sender {
// If this view controller (i.e. SecondViewController) was pushed, like in your case, then
[self.navigationController popViewControllerAnimated:YES];
// If this view controller was presented modally, then
// [self dismissViewControllerAnimated:YES completion:nil];
}
And of course, your view controller hierarchy in storyboard must be like this:
-- UINavigationController -> FirstViewController -> SecondViewController
|
->UITabBarController____|
-...
-...
I've tried the same and got the same result.
My solution was simple, on the push do this :
UINavigationController *firstViewNavigationController = [storyboard instantiateViewControllerWithIdentifier:#"destination"];
firstViewNavigationController.hidesBottomBarWhenPushed = true; // Insert this and set it to what you want to do
[self presentViewController:firstViewNavigationController animated:animated completion:nil];
and then remove your
-(BOOL)hidesBottomBarWhenPushed
{
return YES;
}