iOS - opposite of nil for rightBarButtonItem - ios

I need to make a button reappear after I set it to nil but I can't seem to figure it out.
I set it to nil using:
self.navigationItem.rightBarButtonItem =nil;

When you set the button to nil you destroy (deallocate) it. Just recreate the button. Or, if it's expensive to create for some reason, create another property which holds the button and then use that to restore the rightBarButtonItem.

It's a requirement to set the button to nil? Another approach is to set the button's background alpha to 0, or disable it with setEnabled:NO. If it's a requirement, you have two options:
Store the button as a property and assign the button to the rightBarButtonItem of the navigationItem. Make sure you do all button manipulation to the property.
Create a method to create an instance of UINavigationItem with the button and assign this button to rightBarButtonItem. By the way, if you want to have exactly the same instance you had in the nil assignment, you must use the first option.
Hope it helps!

UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(done)];
[self.navigationItem setRightBarButtonItem:doneButton animated:YES]

Hide the button by setting the reference to nil, however if you want to restore it later, you'll need to hang onto a copy of it so you can reassign it.
UIBarButtonItem *oldButton = self.navigationItem.rightBarButtonItem;
[oldButton retain];
self.navigationItem.rightBarButtonItem = nil;
//... later
self.navigationItem.rightBarButtonItem = oldButton;
[oldButton release];
Or create a property of the barbuttonitem and just pass it whenever you need it.
#property (nonatomic, retain) UIBarButtonItem *rightNavButton;
self.navigationItem.rightBarButtonItem = self.rightNavButton;

Related

Hide UIBarButtonItem from UINavigationBar programatically Swift2

I've tried hiding the thing, but it just appears greyed out in UINavigationController
I found a delete method, but it asks to pass in Anyobject..
Button.delete(AnyObject?)
You can remove the UIBarButtonItem. It's just one type of deallocating the item:
self.navigationItem.rightBarButtonItem = nil
self.navigationItem.leftBarButtonItem = nil

How to assign actions to UINavigationItem backBarButtonItem

I am trying to find a way to stop some of the processes within a detail controller (and let the user know that this is happening) when the back button in the navigation bar is pressed. However, I can't find a way to implement these changes when the button is pressed.
Is there a way to do this?
If you want to raise a user alert/notification before going back, you are really going to have to create your own back bar button item and assign it to self.navigationItem.leftBarButtonItem.
You need to hide the default button using:
self.navigationItem.hidesBackButton = YES;
Then add a target to your new button which does your process cleanup and raises an alert. In the alert handler, pop the controller once the user has acknowledged the alert.
The fastest and easiest way is to use custom back button like below;
-(void)viewDidLoad{
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStyleBordered target:self action:#selector(actionBack)];
[self.navigationItem setBackBarButtonItem:barButtonItem];
}
-(void)actionBack{
//PopViewController
}
Like any other button.
Put this in the .m file.
- (IBAction)saveButton:(id)sender {
//actions
}
Then control drag from the UINavigationBarButton to the IBAction

How can i assign an action to rightbarbuttonitem with an edit style?

I have an edit rightbarbuttonitem in my view in navigation bar. I set it up with the help of storyboard/IB, not programmatically. Now, all i want is to assign an action when the "done" barbuttonitem is pressed (not edit).
Is there a way to achieve it? I tried manually through -(IBAction), but it's not working. Also, i want to perform the action on selected items in UITableView. So if you give me an idea, it would be great.
That button calls the method
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
You can implement it and it will get called everytime your edit/done button gets tapped. All you have to do is check the button's title property to see when it's showing done and when it's showing edit
If you declared your button as an IBOutlet then all you'd need to do is use the synthesised variable on your .m as so:
_yourBarButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(runMethod)];
self.navigationItem.rightBarButtonItem = _yourBarButton;
Then you'd have to declare your run method:
-(void)runMethod
{
//do stuff
}

backBarButtonItem doesn't call action

I would like to call an action when my backButton is clicked but this doesn't seem to be it.
viewDidLoad in rootViewController:
self.navigationItem.backBarButtonItem = [[[UIBarButtonItem alloc]
initWithTitle:#"Logout"
style:UIBarButtonItemStyleDone
target:self
action:#selector(logout)] autorelease];
The title of it is correct but nothing happens.
logout (in the rootViewController)
header:
-(void)logout;
body:
-(void)logout {
NSLog(#"test");
[[User owner] logout];
}
Could anyone tell me how to solve this, since i have no idea. Thanks
You can change only the title of backBarButton. You can try to use viewWillDisappear or viewDidDisappear functions but they could be called not only after you press your button. The leftBarButton is a better solution but this button's view differs from backBarButton's view.
The backBarButtonItem exists specifically to change the appearance of the back button. If you need a custom action, you should consider using leftBarButtonItem instead.

UINavigationController "back button" custom text?

The "back button" of a UINavigationController by default shows the title of the last view in the stack. Is there a way to have custom text in the back button instead?
From this link:
self.navigationItem.backBarButtonItem =
[[UIBarButtonItem alloc] initWithTitle:#"Custom Title"
style:UIBarButtonItemStylePlain
target:nil
action:nil];
As Tyler said in the comments:
don't do this in the visible view controller, but in the view
controller that you'd see if you hit the back button
You can set the text in the Interface Builder:
Select the navigation item of the ViewController that the back button would return to:
In the utilities panel attribute inspector, enter your label for the Back Button:
I would prefer this approach over setting the title in code as in the accepted answer.
Also note, you need to do this in the view controller one level up the
stack. In other words, don't do this in the visible view controller,
but in the view controller that you'd see if you hit the back button.
--Tyler
I use this:
// In the current view controller, not the one that is one level up in the stack
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationController.navigationBar.backItem.title = #"Custom text";
}
I found a handy solution to this by simply setting the title of the controller before pushing another controller onto the stack, like this:
self.navigationItem.title = #"Replacement Title";
[self.navigationController pushViewController:newCtrl animated:YES];
Then, make sure to set the original title in viewWillAppear, like this:
-(void)viewWillAppear:(BOOL)animated
{
...
self.navigationItem.title = #"Original Title";
...
}
This works because the default behavior of UINavigationController when constructing the back button during a push operation is to use the title from the previous controller.
The title of the back button defaults to the previous view's title so a quick trick I use is to place the following code on the previous view's .m file.
-(void)viewWillAppear:(BOOL)animated {
// Set title
self.navigationItem.title=#"Original Title";
}
-(void)viewWillDisappear:(BOOL)animated {
// Set title
self.navigationItem.title=#"Back";
}
in your init method, add the following code:
- (id)initWithStyle:(UITableViewStyle)style {
if(self = [super init]) {
//...
UIBarButtonItem *customBackButton = [[UIBarButtonItem alloc] initWithTitle:#"Back"
style:UIBarButtonItemStylePlain
target:self
action:#selector(goBack)];
self.navigationItem.leftBarButtonItem = customBackButton;
[customBackButton release];
//...
}
return self;
}
then add a simple method, to allow viewcontroller dismissing:
-(void)goBack {
[self.navigationController popViewControllerAnimated:YES];
}
Add the following code in viewDidLoad or loadView
self.navigationController.navigationBar.topItem.title = #"Custom text";
I tested it in iPhone and iPad with iOS 9
Adding to rein's answer. Note from Apple's docs that the declaration of backBarButtonItem is this:
#property(nonatomic, retain) UIBarButtonItem *backBarButtonItem
Therefore, rein's answer will leak memory because the synthesized setter will retain the instance you pass it, which is never released explicitly. You can remedy this by using autorelease
self.navigationItem.backBarButtonItem =
[[[UIBarButtonItem alloc] initWithTitle:#"Custom Title"
style:UIBarButtonItemStyleBordered
target:nil
action:nil] autorelease]; //<-- autoreleased
Or you could point a variable at the instance so you can explicitly release it later:
UIBarButtonItem* item = ...
self.navigationItem.backBarButtonItem = item;
[item release];
Hope this helps!
- (void)viewDidLoad {
[super viewDidLoad];
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStylePlain target:nil action:nil];
self.navigationItem.backBarButtonItem = backButton;
[backButton release];
}
I've discovered something interesting.
If you subclass the UINavigationController and override the pushViewController:animated: method and do something like this: (bear in mind that I'm using ARC)
UIBarButtonItem *backButton = [[UIBarButtonItem alloc]
initWithTitle: #"Back"
style: UIBarButtonItemStyleBordered
target: nil action: nil];
viewController.navigationItem.backBarButtonItem = backButton;
[super pushViewController:viewController animated:animated];
Then for all ViewControllers that are pushed with your navigation controller will have the "Back" button in them automatically. If you want to change the text for certain view controllers you can try and maybe cast the viewcontroller to a certain class or your own custom protocol (which your viewcontroller inherits from which could have a method like backButtonText or something silly like that) which can give you certain information on the viewcontroller that's coming in sothat you can customize the back button text for it. Now the back button text is taken care of in a place which should hold the responsibility solely. I have to admit that creating a new button to change the text sucks, but oh well.
Can anyone think of a reason why not to do it like this? Atleast you don't have to fiddle with viewcontroller titles or have to remember to create a new back button before pushing the viewcontroller on the navigation controller.
rein's answer works well.
Note that if you push more than one view controller, the changed back button title will appear for each of them, which may not be what you want.
In that case, you'll need to create the custom UIBarButtonItem each time you push a view controller.
Also, make sure you do it before pushing the view controller, otherwise you will get a screen hiccup as the title changes.
Expanding on Aubrey's suggestion, you can do this in the child view controller:
create two variables for storing the old values of the parent's navigationItem.title and the parent's navigationItem
UINavigationItem* oldItem;
NSString* oldTitle;
in viewDidLoad, add the following:
oldItem = self.navigationController.navigationBar.topItem;
oldTitle = oldItem.title;
[oldItem setTitle: #"Back"];
in viewWillDisappear, add the following:
[oldItem setTitle: oldTitle];
oldTitle = nil; // do this if you have retained oldTitle
oldItem = nil; // do this if you have retained oldItem
It's not perfect. You will see the the title of the parent view change as the new controller is animated in. BUT this does achieve the goal of custom labeling the back button and keeping it shaped like a standard back button.
Put this into you viewDidLoad, hope it will result into what you are looking for
UIBarButtonItem *backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Close"
style:UIBarButtonItemStylePlain target:nil action:nil];
self.navigationItem.backBarButtonItem = backBarButtonItem;
[backBarButtonItem release];
if You want to set title in ARRIVING controller (sometimes more logic..)
in swift 3 do:
func setBackButtonNavBar(title: String, delay: Double){
let when = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: when, execute: { () -> Void in
if let navBar = self.navigationController?.navigationBar{
navBar.backItem?.title = title
}
})
}
in upcoming controller:
override func viewDidLoad() {
super.viewDidLoad()
self.setBackButtonNavBar(title: "back", delay: 0.3)
}
usually I put self.setBackButtonNavBar in a controller extension.
I know this is an old question and the answers' kind of out updated!
The easy way is to do this in parent ViewController:
i.e the one that takes you to next view controller.
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "Custom text here", style: .plain, target: nil, action: nil)
Doing this in code remove the back button style of the UINavigationConroller. If you add a Navigation Item in each of yours views, you can set the title of the back botton in the StoryBoard.

Resources