Back button covers up a previous UIBarButton when pushViewController is called - ios

My app is navigated by a slide out menu from the left. On top of each viewController is a left UIBarButton titled "Navigation", that when touched, opens the slide out menu without having to do the drag effect. I am implementing speech commands into my app, and if a user speaks "Go to Finances", it segues to a viewController titled FianceViewController through instantiateViewController to pushViewController.
This all works fine, the only problem is the back button associated with push segue covers up my "Navigation" button in the left slot of the UINavigationBar. Using self.navigationItem.hidesBackButton = YES; hides both the back button and my "Navigation" button. Is there anyway not make a back button appear when the push happens, but still allow my previously created "Navigation" bar button to be seen and used? Or is there another type of segue that I can do other than push if this UIBarButton dilemma cannot be solved?
Section of code that segues when spoken:
if ([title isEqualToString:#"FINANCES"])
{
FinanceViewController *fvc = [[self storyboard] instantiateViewControllerWithIdentifier:#"finance"];
[[self navigationController] pushViewController:fvc animated:YES];
}

How are you adding the navigation button?
I would try to add it after hiding the back button, something like this:
self.navigationItem.hidesBackButton = YES;
UIButton *navigationButton = [[UIButton alloc] initWithFrame:CGRectMake(15.0, 15.0, 100.0, 32.0)];
self.navigationController.navigationBar.backItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:navigationButton];

Instead of hiding my back button, I figured out I could simply write over it! Using fvc.navigationItem.leftBarButtonItem = self.navigationItem.leftBarButtonItem; before pushViewController, allows the "navigation" button to override the back button.

Related

iOS Navigation Bar: change left bar button from menu to back

I have an app that uses a side menu and has a few main screens that can be accessed from the menu and others that can only be accessed from these screens.
What I want is to have a menu button on the navigation bar that opens the menu and can only be visible on the main screens. On the other screens I want to have a back button, instead of the menu button.
I've already put the menu button like this:
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"IconMenu"] style:UIBarButtonItemStylePlain target:self.revealViewController action:#selector(revealToggle:)];
But I can't figure out how to change it with the back button when I need it.
Assuming than by "main screens" you mean root (first) view controllers in the navigation view controllers corresponding to the selected side menu items, this might be a solution for your problem: you can create a superclass for all your view controllers, say MyBaseViewController and rewrite viewWillAppear: method, that will determine whether it should have a default back button or a "revealSideMenu" button, based on whether it's a "main screen" or not.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (self == [self.navigationController.viewControllers firstObject]) {
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"IconMenu"] style:UIBarButtonItemStylePlain target:self.revealViewController action:#selector(revealToggle:)];
}
}
you can do that in 2 different ways:
the first is in the viewDidAppear check if the back button is already present (when you push a VC the back button automatically added but is avalaible programmatically only after the viewDidAppear) and then decide to add or not the menu button,
the second is add a parameter to your VC init method like isRoot or hasMenu or whatever you like to name it, and using that flag decide to add the menu or the back button
if you chose to add your own back button you have to call this method in your back selector
[self.navigationController popViewControllerAnimated:YES];
The easiest way, IMO, is just to click on the title bar of the first ViewController and in the Attribute Inspector (⌥+⌘+4) change the Navigation Item info the way you want: Title -> what will show up in the back button* or if you want it to say something other than the Title of the first ViewController or the word "Back" you can just put it in the Back Button field.
*If the Title of the second ViewController is too long for it to fit it will be replaced with the word "Back" (and if the word "Back" doesn't fit it will only have the arrow sign).

Is it possible to show a real Popover instead of default slide-out menu when using a UISplitViewController?

I am currently working with a UISplitViewController and instead of having this default slide-out-menu, i want a real UIPopover that appears if i click the UIBarButtonItem. What do i have to do and is there an easy way of configuring this ?
You first need to overwrite the left bar button item, with the button that can be used to display the popover.
Use the following -
UIBarButtonItem *barBtn = [[UIBarButtonItem alloc] initWithTitle:#"Popover" style:UIBarButtonItemStylePlain target:self action:#selector(presentPopover:)];
self.navigationItem.hidesBackButton = NO;
self.navigationItem.leftBarButtonItem = nil;
Now you can use the target added, and then perform the associated function, as per your choice.
-(IBAction)presentPopover:(id)sender
{
// Perform your operations
}
Then just use a popover view controller instead with the same content you would have used in the splitview pane that slides out.

Back, Edit and Add buttons in navigation bar of TableView with Storyboard on iOS

I'm facing some problems in implementing a tableview, with "Back", "Edit" and "Add" buttons on the navigation bar.
The tableview is reached by clicking on a row of another tableview, so the "Back" button is added automatically.
With the storyboard I've added the "Add" button to the navigation bar.
With code I've added the "Edit" button (I used code, since if I add the button with the storyboard, I don't know how to reproduce the "Edit" standard behavior...):
self.navigationItem.leftBarButtonItem = self.editButtonItem;
The problem is that, in this way, the "Edit" button hides the "Back" button on the navigation bar.
At this point, I've two questions:
Is it possible with storyboard to add a third button on the navigation bar?
In case I've to do this programmatically, I know that I can do this as follows:
UIButton *button = [UIButton buttonWithType: UIButtonTypeRoundedRect];
[button setFrame:CGRectMake(width-90,6,50,30)];
[button setTitle:#"Edit" forState:UIControlStateNormal];
button.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
[self.navigationController.navigationBar addSubview:button];
But how can I implement via code the standard behavior of the "Edit" button? I mean, I click "Edit" and the button becomes "Done" and the rows become deletable...
Thanks in advance,
yassa
Incase anyone else should happen to stumble onto this question as well the solution is pretty easy. UINavigationItem has a property for rightItems wich is just an array of UIBarButtonItems. Put both an add button and an edit button into an array and assign it to rightItems and your done :-) And here is an example code snippet:
UITableViewController *table = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(insertNewObject:)];
NSArray *barButtons = [NSArray arrayWithObjects:table.editButtonItem, addButton, nil];
table.navigationItem.rightBarButtonItems = barButtons;
First, the Apple docs say 'you do not add subviews to a navigation bar directly'. Don't know if this is enough to get the app bounced from the store, but it's not considered "proper".
Second, you can add more than three buttons to a UINavigationItem in iOS 5 but not in iOS 4 or earlier.
Finally, I'd leave the edit button top right and back top left. That's where people expect them. If I wanted an add button (and are on iOS 5), I'd place it next to the edit button.
Sorry; no help on storyboards. Don't know anything about them.

creating button for popover view anchor at run time

This may not be possible, but I'm hoping someone will have an idea how to do it.
I have an app I'm porting from iPhone only to Universal. On the iPhone, I'm using a Tabbed application. I use three tabs for the normal data to be displayed. I have a forth tab that's only displayed if certain conditions are met. To add the tab, I do:
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
UITabBarController *tabController = (UITabBarController *) self.rootViewController;
NSMutableArray* newArray = [NSMutableArray arrayWithArray: tabController.viewControllers];
[newArray addObject: [theStoryboard instantiateViewControllerWithIdentifier: #"AdditionalView-Phone"]];
[tabController setViewControllers:newArray animated:YES];
}
For the iPad, I have enough space on the initial view to display everything from the main three tabs in the iPhone UI. So all I need is one additional (small) view for the "Additional" data. I wanted to do it using a popOver view, so I set up the initial view with a Nav bar and popover button as in the Utility App template. But now I'm stuck. I can't figure out how to create that popover button at run time and make it do the segue to the popOver view properly. I can add the button like this:
UIBarButtonItem *flipButton = [[UIBarButtonItem alloc] initWithTitle: #"Modem" style: UIBarButtonItemStylePlain target: self action: #selector(togglePopover:)];
self.navBar.topItem.rightBarButtonItem = flipButton;
but I get an exception: 'NSInternalInconsistencyException', reason: 'UIStoryboardPopoverSegue must be presented from a bar button item or a view.' I'm pretty sure this is because I don't have an anchor set for the popOver segue. The button doesn't exist in the storyboard, so I can't set it there. And I can't seem to find an API to set it at run time.
I also tried creating the button in IB, but not in the view hierarchy, and then just setting the rightBarButtonItem property to my existing button. That also works, but I still can't set that button as the anchor for the popover view. I can set the Navigation Bar as the anchor, but that makes it anchor to the title in the nav bar, which looks silly.
Any ideas?
I had the same problem and solved it by creating a UIBarButtonItem in the Storyboard for the view controller but not part of the view hierarchy.
In IB, Drag a bar button item to the dark bar below the view controller view, drop it next to the "First Responder" and "View Controller" icons. Create a (strong) IBOutlet for it. Then create a popover segue from it to the destination view controller by dragging from the bar button item to the destination. It seems like this is the only way to set it as the anchor. Choosing it as the anchor for an existing segue does not work (looks like an IB bug).
In viewDidLoad you can assign this bar button item to the navigationItem (or where ever you like) and the segue works as expected.
I was curious about this too so I made a quick test project. You're right, there doesn't seem to be a way to configure the popover segue at runtime or add an anchor point to a button that's not in the view hierarchy using Interface Builder.
My solution was to set everything up in IB with the UIBarButtonItem visible and connected to an IBOutlet property, then remove it from the navigation bar in -viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = nil;
}
Then I simply add it back or remove it by tapping another button:
- (IBAction)toggleBarButtonItem:(id)sender
{
UIBarButtonItem *item = (self.navigationItem.rightBarButtonItem == nil) ? self.popoverBarButtonItem : nil;
[self.navigationItem setRightBarButtonItem:item animated:YES];
}
You could conditionally keep or remove the button in -viewDidLoad the same way. The segue remains anchored to the UIBarButtonItem.
I'm gonna try making a dummy view that's the size and shape of the views I want to present the popover from, wire that to the segue popover target, and then move the view to the right position in prepareForSegue:sender:
I'm not sure this is exactly what you want, but this is what I would do. Create a button and set it up with some target/action. Call that target/action method
presentPopover:(UIButton *)sender;
Then in the presentPopover method, say
UIViewController *customAdditionalViewController = [[MySpecialVC alloc] init];
//Configure the customAdditionalViewController
//Present the customAdditionalViewController in a Popover
UIPopoverController *popover = [[UIPopoverController alloc] initWithViewController:customAdditionalViewController];
//Set popover configurations
[popover presentPopoverFromRect:sender.frame inView:self.view permittedArrowDirections:/*whatever you want*/ animated:YES];
That is how I would handle your use case.

Add another button next to the "back" button on the left of a UINavigationBar

I've tried this for hours but I still cannot solve it.
When using UINavigationController and push a new view controller on top, I got a free "back" button on the left of the navigation bar. I want another button just next to it (to show a popover menu). I wonder what is the correct way to do that. Or I have to hide the free back button and make the same one by myself? If that's the case, I also need to pop the current view controller when pressing my own back button, right?
Thanks for your help.
As stated by steipete in the comment to the question, this is possible starting from iOS 5. You can use
self.navigationItem.leftItemsSupplementBackButton = YES;
and then you just need to add an UIBarButtonItem as leftButton to get a second button after the back button
UIBarButtonItem *secondButton = [[UIBarButtonItem alloc] initWithTitle:#"Second" style:UIBarButtonItemStylePlain target:self action:#selector(yourAction)];
self.navigationItem.leftBarButtonItem = secondButton;
SWIFT 5 this worked for me. Thanks
self.navigationItem.leftItemsSupplementBackButton = true

Resources