I'm adding a custom back button to a UINavigationBar in UIViewController like follows:
-(void)viewDidLoad {
UIBarButtonItem *customBackButton = [[UIBarButtonItem alloc] initWithTitle:#" " style:UIBarButtonItemStyleBordered target:self action:#selector(navigateBack)];
[customBackButton setBackButtonBackgroundImage:barBackBtnImg forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[customBackButton setBackButtonBackgroundImage:barBackBtnImgHighlighted forBarMetrics:UIBarMetricsDefault];
self.navigationItem.backBarButtonItem = customBackButton;
}
It works perfectly until I push a modal UIViewController and dismiss it again. What happens is that the standard iOS 7 back button is drawn over my custom back button.
This looks like an iOS 7 bug. Any idea how to work around it?
If you move your code to viewWillAppear:(BOOL)animated it should work. It's somewhat a hack, but it should work.
Related
In iOS 7 there's the new swipe to pop gesture: You swipe from left to right on the left side of your screen and the UINavigationController pops back to the previous UIViewController.
When I create a custom back button like this, the swipe to pop gestures doesn't work anymore:
UIBarButtonItem *customBackButton = [[UIBarButtonItem alloc] initWithTitle:#" " style:UIBarButtonItemStyleBordered target:self action:#selector(navigateBack)];
[customBackButton setBackButtonBackgroundImage:barBackBtnImg forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[customBackButton setBackButtonBackgroundImage:barBackBtnImgHighlighted forBarMetrics:UIBarMetricsDefault];
self.navigationItem.backBarButtonItem = customBackButton;
How can I use a custom back button and have the native swipe to pop gesture?
Update:
That's what's happening in navigateBack:
- (void)navigateBack {
[self.navigationController popViewControllerAnimated:YES];
}
There is no need to add your own gesture recognizer. The UINavigationController already does that for you.
You need to set the delegate for the interactivePopGestureRecognizer before enabling it.
Do the following two things:
self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
[self.navigationController.interactivePopGestureRecognizer setEnabled:YES];
Just add the following line of code:
[self.navigationController.interactivePopGestureRecognizer addTarget:self action:#selector(handleGesture:)];
You can add your own UIGestureRecognizer and pop the UIViewController yourself. See the docs for further info.
I use
[[UINavigationBar appearance] setBackIndicatorImage:[UIImage imageNamed:#"nav_back.png"]];
[[UINavigationBar appearance] setBackIndicatorTransitionMaskImage:[UIImage imageNamed:#"nav_back.png"]];
[UIBarButtonItem.appearance setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -64) forBarMetrics:UIBarMetricsDefault];
To avoid crashes you have to be careful how you add and remove your custom back selector. The reason is that the navigation controller stays around while you pushing popping controller.
As already stated after adding your custom back button+selector, you should do the following in viewDidApear.
if ([self.navigationController respondsToSelector:#selector(interactivePopGestureRecognizer)])
{
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
[self.navigationController.interactivePopGestureRecognizer addTarget:self action:#selector(navigateBack)];
}
Then in viewWillDisapear do
if ([self.navigationController respondsToSelector:#selector(interactivePopGestureRecognizer)])
{
[self.navigationController.interactivePopGestureRecognizer removeTarget:self action:#selector(performCompletion)];
}
The timing of these calls is a key. You can run into crashes otherwise, see more details on the reason in here
There is a new gesture recognizer UIScreenEdgePanGestureRecognizer. You can add it to your view and handle respectively (call navigateBack), replicating view controllers navigation behaviour.
What did you do in "navigateBack" ?
Use this method like this :
- (void)navigateBack
{
[self.navigationController popViewControllerAnimated:YES];
}
try adding this into the custom back button
self.navigationController.interactivePopGestureRecognizer.delegate = (id)self;
I'm trying to create a custom navigation bar with title and two custom baritems.
What I've done so far:
1. subclass a UINavigationBar
2. override -(void) drawRect:(CGRect)rect method, to draw image as a background
Now I get stuck when making right bar button item.
In my CustomBar class I've overriden pushNavigationItem method as follows:
- (void)pushNavigationItem:(UINavigationItem *)item animated:(BOOL)animated {
[super pushNavigationItem:item animated:NO];
item.rightBarButtonItem.customView.frame = CGRectMake(250, 5, 60,30);
}
and in my view controller I've done something like:
UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithCustomView:myButton];
self.navigationController.navigationItem.rightBarButtonItem = barButton;
[self.navigationController.navigationBar pushNavigationItem:self.navigationItem animated:NO]
but I always get SIGABRT when calling
[super pushNavigationItem:item animated:NO];
If I leave that line out, everything runs fine, but there is no button in the navigation bar.
What is the proper way to add custom bar button item to custom navigation bar?
EDIT:
For clarification, I've added an image.
This is what I need.
I'm trying to create the logout button on the right
Have you tried removingnavigationController while setting the item ? I used to do that for setting the title, never used to get the title.
Try [[self navigationItem] setRightBarButtonItem:yourButton];
In your case :
UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithCustomView:myButton];
self.navigationItem.rightBarButtonItem = barButton;`
I have following code which add BackButton on my view's navigation item's tabbar. It works fine.
// Add back button
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStylePlain target:nil action:nil];
[view.navigationController setNavigationBarHidden:NO animated:YES];
view.navigationItem.backBarButtonItem = backButton;
view.navigationController.navigationBar.barStyle = UIBarStyleBlack;
[backButton release];
I use following line to navigate to my new view controller but it gets presented with default animation.
[view.navigationController pushViewController:viewController2 animated:YES];
I want to change the way it gets presented so I tried to do it following way.
[viewController2 setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[view.navigationController presentModalViewController:viewController2 animated:YES];
This works fine but I lost my BackButton..!! Is there anyway to present my new view controller with specific transition style and also keep my back button as is?
Thanks.
I found the answer to your question. Put a navigation bar on your viewController2 and add a bar button to it using either interface builder or using code. Then in the action of button press
In your viewController2.m write this function and link it up with the button press if you have added the bar button through interface builder.
-(void) backButtonPressed : (id) sender
{
[self dismissModalViewControllerAnimated:YES];
}
This should solve your problem.
Doing a pushViewController will carry forward the navigationBar and all for you but in your case presenting a viewController as modalViewController will not give you the navigationBar by default so you have to add it manually in your modalViewController which is viewController2 in your case.
Please let me know if you are still facing problems. We can fix it soon and save you some time and frustration.
Cheers!!!
I am trying to show the UIToolBar in the RootView of a UISplitView application, the code is the following:
self.navigationController.toolbarHidden = NO;
UIBarButtonItem *refreshItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
target:self
action:#selector(refresh:)];
self.toolbarItems = [NSArray arrayWithObjects:refreshItem, nil];
[refreshItem release];
However, what I see is:
There's black bar on top (I don't know where this came from, I don't need this) also the bar at the bottom, is there a way to resize it?
What I want is to get something like this:
Using something like this you can add a bar button item to the top of the controller:
UIBarButtonItem *refreshItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:#selector(refresh:)];
self.navigationItem.leftBarButtonItem = refreshItem;
[refreshItem release];
You will make the button appear in the main view controller's title bar, as it's meant to be.
If you want to make the button appear in the bottom of the navigation controller you could try using this approach, instead:
UIBarButtonItem *refreshItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:#selector(refresh:)];
[self setToolbarItems:[NSArray arrayWithObjects:refreshItem, nil animated:YES]];
[self.navigationController setToolbarHidden:NO]; //optional, don't remember if it's required ...
[refreshItem release];
For this piece of code to work correctly the side controller has to be a UINavigationController, otherwise you wouldn't be able to create and handle the toolbar. I tried this approach in a clean project and the toolbar renders perfectly.
I had the same issue and Just fixed it, Due to moving the code out of the Viewdid Load to lower down the Page,
As I had previous put in
- (UIBarButtonItem *)barButtonItem {
Moving the Code You used to under that, Worked and fixed the issue
Stewart
Just a note for anybody else who stumbles upon this question. I was having the same issue as adit. The problem turned out to be I was setting up and unhiding the toolbar in the viewDidLoad method instead of the viewWillAppear method. Those gaps are caused by setting up the toolbar before the view knows it's being displayed in landscape mode.
The safest and easiest solution is to setup the UINavigationController to display the toolbar and navigation bar in Interface Builder.
If it looks as expected in IB, it is very unlikely it will change at run-time.
If the toolbar is to be shown/hidden when navigating you should add the cod to do so in viewWillAppear: and allways call the super implementation, or unexpected things may occurs. Something like this tends to give the best results in a consistent manner:
-(void)viewWillAppear:(BOOL)animated;
{
[super viewWillApplear:animated];
[self.navigationController setToolbarHidden:NO
animated:animated];
}
Also make sure to show/hide the toolbar as need in viewWillAppear: for all view controllers in your navigation stack for best result.
I know that it could seem strange but i need to add a back button on the navigation Bar of the first navigationController's view. I tried like this:
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Foo" style:UIBarButtonItemStyleBordered target:self action:#selector(foo:)];
self.navigationItem.backBarButtonItem=backButton;
if instead of backBarButtonItem i write leftBarButtonItem the button is showed. My problem is that i need an arrow button as the normal back button. Is this possible?
Usually this works out of the box, but sometimes with modal views / action sheets you may need this. Just before you instantiate your viewcontroller and push it onto navigationcontroller stack, try
UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithTitle: #"Back" style: UIBarButtonItemStyleBordered target: nil action: nil];
[[self navigationItem] setBackBarButtonItem: newBackButton];
[newBackButton release];
DetailViewController *detailVC = [[DetailViewController alloc]init];
[self.navigationController pushViewController:detailVC animated:YES];
[detailVC release];
I don't think you can do that on the first NavigationController view, because you need to set the backBarButtonItem property in the parent controller, before the child controller is pushed. Also, according the to the Apple docs, the target & action of the backBarButtonItem must be nil.
This question about creating a left-arrow button on a UIToolbar may give you some ideas of how you could work around this using a custom image (for the leftBarButtonItem).
or you could also do the following - I prefer this method. I got this from a different post.
Use following psd that I derived from http://www.teehanlax.com/blog/?p=447
http://www.chrisandtennille.com/pictures/backbutton.psd
Then I just create a custom UIView that I use in the customView property of the toolbar item.
Works well for me.
Hope that helps a little
Of course you can do this. You just need to change the leftBarButtonItem's title to back
then you will get a nice left arrow button with the title back. Then you just change the selector to actually perform a method when the button is clicked. So #selector(foo:)
Here some code on how to achieve the above:
self.navigationItem.leftBarButtonItem.style = UIBarButtonItemStyleDone;
self.navigationItem.leftBarButtonItem.title = #"Back";
self.navigationItem.leftBarButtonItem.target = self;
self.navigationItem.leftBarButtonItem.action = #selector(endTextEnteringButtonAction:);
Let me know if that helps.
Apple Document says:
When this navigation item is immediately below the top item in the stack, the navigation controller derives the back button for the navigation bar from this navigation item.
So If your navigation item is the top of the Stack (as we are talking here) you can't add the back button to the navigation controller, simply because no place he can navigate back to it because it's the top item in the stack.
Updated Answer :
After I searched I found work a round to make a back button in your root view controller in Navigation controller in these link
It's very simple :)
[self.navigationItem setHidesBackButton:YES animated:YES];
UIBarButtonItem* backButton = [[UIBarButtonItem alloc] initWithTitle:#"Start" style:UIBarButtonItemStyleBordered target:self action:#selector(initializeStuff)];
self.navigationItem.leftBarButtonItem = backButton;