I need to hide the right button in the Navigation Bar, then unhide it after the user selects some options.
Unfortunately, the following doesn't work:
NO GOOD: self.navigationItem.rightBarButtonItem.hidden = YES; // FOO CODE
Is there a way?
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];
Personally, in my apps I make my nav buttons into #properties, so that I can trash & recreate them at will, so something like:
//mycontroller.h
UIBarButtonItem *rightNavButton;
#property (nonatomic, retain) UIBarButtonItem *rightNavButton;
//mycontroller.m
#synthesize rightNavButton;
- (UIBarButtonItem *)rightNavButton {
if (!rightNavButton) {
rightNavButton = [[UIBarButtonItem alloc] init];
//configure the button here
}
return rightNavButton;
}
//later, in your code to show/hide the button:
self.navigationItem.rightBarButtonItem = self.rightNavButton;
For Swift 3
if let button = self.navigationItem.rightBarButtonItem {
button.isEnabled = false
button.tintColor = UIColor.clear
}`
Set reference to nil:
current_controller_in_navcontroller.navigationItem.rightBarButtonItem = nil;
Also be sure to call this in the controller currently shown by the navController, not for the navController itself.
Show:
[self.navigationItem.rightBarButtonItem.customView setAlpha:1.0];
Hide:
[self.navigationItem.rightBarButtonItem.customView setAlpha:0.0];
You can even animate its showing/hiding
[UIView animateWithDuration:0.2 animations:^{
[self.navigationItem.rightBarButtonItem.customView setAlpha:1.0];
}];
If you have only one bar button item in the right side you can use this one,
self.navigationItem.rightBarButtonItem = nil;
Suppose if you have multiple bar button in the right side, for example suppose you have two bar button items(search button and filter button) in the right side of your navigation item. Now the right bar button items are
self.navigationItem.rightBarButtonItems = [searchItem,filterItem]
and you have to hide only search button, you can use like,
self.navigationItem.rightBarButtonItems = [filterItem]
Now what happening is, you can completely hide the search button from the navigation item and the filter item comes in the place of search item
Here's Matt's solution updated for Storyboards & ARC. Remember, IBOutlets are __weak by default, so you need to change that to strong for it not to be released too early.
#interface MAGTableViewController () <UITextFieldDelegate>
#property (strong, nonatomic) IBOutlet UIBarButtonItem *rightBarButton;
#end
#implementation MAGTableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self.navigationItem setRightBarButtonItem:nil];
}
- (IBAction)rightBarButtonItemTapped:(id)sender
{
[self.view endEditing:YES];
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[self.navigationItem setRightBarButtonItem:self.rightBarButton];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self.navigationItem setRightBarButtonItem:nil];
}
#end
Credit has to go to learner for this answer which the answer is from this question:
hide and show left navigation bar button on demand in iOS-7
This is the answer, which is far more simple.
//hide and reveal bar buttons
-(void) hideAndDisableLeftNavigationItem
{
[self.navigationItem.leftBarButtonItem setTintColor:[UIColor clearColor]];
[self.navigationItem.leftBarButtonItem setEnabled:NO];
}
-(void) showAndEnableLeftNavigationItem
{
[self.navigationItem.leftBarButtonItem setTintColor:[UIColor blueColor]];
[self.navigationItem.leftBarButtonItem setEnabled:YES];
}
Then you just reference the method where you require it like within an (IBAction) like so:
[self hideAndDisableLeftNavigationItem];//[self showAndEnableLeftNavigationItem]; to show again
I tried all other methods and none worked, even referencing my button as a #property (...) UIBarButtonItem.... and nothing worked until I found this.
SWIFT 2.2
In swift 2.2 self.navigationItem does not work. Instead create an outlet of the NavigationItem (I named it below "nav") and use it.
Also the following suggestion did not work for me using Xcode 7.3 and swift 2.2
nav.leftBarButtonItem?.customView?.hidden = true
So I used the idea of #Matt J above as follows (I have 2 items on the left):
Create outlets for the items in the navigation bar and variables to store them
#IBOutlet weak var settingItem: UIBarButtonItem!
#IBOutlet weak var logoItem: UIBarButtonItem!
var sav_settingItem: UIBarButtonItem = UIBarButtonItem()
var sav_logoItem: UIBarButtonItem = UIBarButtonItem()
Save the items in viewDidLoad()
sav_settingItem = nav.leftBarButtonItems![0]
sav_logoItem = nav.leftBarButtonItems![1]
To HIDE set them to nil
nav.leftBarButtonItem = nil
nav.leftBarButtonItem = nil
To SHOW them
if (nav.leftBarButtonItem == nil) {
nav.leftBarButtonItem = sav_settingItem
nav.leftBarButtonItems?.append(sav_logoItem)
return
}
Show:
[self.navigationItem.rightBarButtonItem.customView setHidden:NO];
Hide:
[self.navigationItem.rightBarButtonItem.customView setHidden:YES];
My solution:
self.navigationItem.rightBarButtonItem.customView.hidden=NO;
Swift 2:
Trick!
Hide:
if let btn = self.tabBarController!.navigationItem.rightBarButtonItem {
btn.enabled = false
btn.title = ""
}
Show:
if let btn = self.tabBarController!.navigationItem.rightBarButtonItem {
btn.enabled = true
btn.title = "ButtonName"
}
For swift 5 to hide rightBarButtonItem
self.navigationItem.rightBarButtonItem?.customView?.isHidden = true
In swift 4 I has a trick to show / hide right or left button:
Step 1: Create a IBOutlet button in view controller:
#IBOutlet var navigationItemButton: UIBarButtonItem!
Step 2: Create Hide button function:
func hideNavigationButton() {
navigationItemButton.isEnabled = false
navigationItemButton.tintColor = UIColor.clear
}
Step 3: Create Show button function:
func showNavigationButton() {
navigationItemButton.isEnabled = true
navigationItemButton.tintColor = UIColor.white
}
Step 4: Just call the functions that you want, use hideNavigationButton() to hide, and showNavigationButton() to show the button.
Regards!
You can use below code:
self.navigationItem.rightBarButtonItem?.image = nil
self.navigationItem.rightBarButtonItem?.isEnabled = false
Show:
//set navigationItem tint color white
self.navigationItem.rightBarButtonItem.tintColor = [UIColor whiteColor];
Hide:
//set navigationItem tint clear white
self.navigationItem.rightBarButtonItem.tintColor = [UIColor clearColor];
Assume you can reference the specific bar button as variable xxxButton
(please open Assistant Editor, Control+Drag xxx button to YourViewController class as outlet "xxxButton").
or you can use something like let xxxButton = navigationBar.buttons[1]
Hide
xxxButton.customView = UIView()
or
navigationItem.rightBarButtonItems?.remove(at: (navigationItem.rightBarButtonItems?.index(of:xxxButton)!)!)
Show
xxxButton.customView = nil
or
navigationItem.rightBarButtonItems?.insert(newElement: xxxButton, at:SOME_INDEX)
Hope helpful.
To hide:
if let topItem = self.navigationController?.navigationBar.topItem {
topItem.rightBarButtonItem = nil
}
Set the the title to empty first and after swlwction just set again.
Related
I have a property:
#property (strong, nonatomic) IBOutlet UIBarButtonItem *backButton;
It gets set like this:
UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemPlay target:self action:#selector(goBack:)];
backItem.imageInsets = UIEdgeInsetsZero;
UIToolbar *backToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 44, 44)];
backToolbar.userInteractionEnabled = YES;
[backToolbar setTransform:CGAffineTransformMakeScale(-1, 1)];
backToolbar.items = [NSArray arrayWithObjects:backItem, nil];
backToolbar.backgroundColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0];
backToolbar.clipsToBounds = YES;
self.backButton = [[UIBarButtonItem alloc] initWithCustomView:backToolbar];
self.backButton.enabled = YES;
self.backButton.imageInsets = UIEdgeInsetsZero;
Which I would have thought would set the selector to this:
- (IBAction)goBack:(id)sender {
NSLog(#"goBack pushed");
[self.iframeView goBack];
}
But goBack pushed is never logged out when I click the button, though the iframeView (just a UIWebView) does go to the previous page.
I've also tried setting the action like this (set right below the above code):
[self.backButton setTarget:self];
[self.backButton setAction:#selector(goBack:)];
Any ideas how I can adjust the code such that the selector is called when I push the back button?
Did you create your backButton from storyboard (because you declare it as an IBOutlet)?
If you already create it from storyboard then you can simply Ctrl-Left Click to drag the button into your implementation file .m where the - (IBAction)goBack:(id)sender is to create the selector.
UPDATE:
I just noticed you said this
But goBack pushed is never logged out when I click the button, though
the iframeView (just a UIWebView) does go to the previous page.
UIWebView has the goBack function already. So by setting
[self.backButton setAction:#selector(goBack:)];
When the button is pressed it will called the goBack function of the UIWebView.
All you have to is give it a different name:
[self.backButton setAction:#selector(backButtonPressed:)];
- (IBAction)backButtonPressed:(id)sender{
NSLog(#"goBack pushed");
[self.iframeView goBack];
}
I tried your code and I found a line of code is missing which is why the selector goBack: is not triggered. If I am not wrong the button "Play" is not visible when you compile
self.navigationItem.rightBarButtonItem = self.backButton;
As I observed you have created the bar button, toolbar programmatically, also you don't need the #property (strong, nonatomic) IBOutlet UIBarButtonItem *backButton; if your not using it else where in the code or you have to omit the IBOutlet.
Hope these helps.
I have some code that creates barbuttonitem Edit and if you click it and begin editing, changes the button to Done.
When I first create the button I set its action to Edit. However, once the user is editing, I want to change the action of the renamed button to Save.
I thought I had save firing but somewhere along the line it stopped working possibly when I added a method in the middle to enable and disable the button.
Can anyone suggest the proper way to change the action of a bar button item?
Here is my code:
//code to create button which sets action to gotoEdit method
UIBarButtonItem *editButton = [[UIBarButtonItem alloc] initWithTitle:#"Edit" style:UIBarButtonItemStylePlain target:self action:#selector(gotoEdit)];
self.navigationItem.rightBarButtonItem = editButton;
}
-(void) gotoEdit {
self.navigationItem.rightBarButtonItem.title = #"Done";
_editButton.target = self;
_editButton.action = #selector(save);//changes action to save method
//some other code to make a textview editable, change its background color and so forth.
}
-(void) save {
NSLog(#"save method firing");
}
//I added the following methods at about the same time the save method stopped firing but not sure if they are related. (Probably not but including them anyway.)
//detect change on screen
- (void)textViewDidChange:(UITextView *)textView{
self.didChange=YES;
[self updateSaveButton];
}
-(void) updateSaveButton
{
self.editButton.enabled = (_didChange == TRUE);
}
It is better to use a bool instead of adding and removing the button's action.
-(void) gotoEdit {
if(!isEditing){
// Prep for editing
self.navigationItem.rightBarButtonItem.title = #"Done";
isEditing = true;
}else{
// Prep for saving
self.navigationItem.rightBarButtonItem.title = #"Edit";
isEditing = false;
}
}
For future reference you can remove a button's selector like this:
[_editButton removeTarget:self
action:#selector(gotoEdit)
forControlEvents:UIControlEventTouchUpInside];
I am creating a simple category of UIViewController which adds the possibility to show a button simply on top of the view to display a chat window.
#interface UIViewController (ChatButton)
- (void)showChatButtonFromTop;
- (void)showChatButtonFromBottom;
- (void)hideButton;
#end
Now in the method I create a button and display it:
- (void)showChatButtonFromTop
{
UIButton* chatBtn = [self constructButtonWithWidth:buttonAxisSize X:buttonX Y:buttonY];
[self.view addSubview:chatBtn];
}
But I also need to hide the button:
- (void)hideButton
{
// confusion!
}
How do I get that button? Categories don't allow for properties, so how do I store the reference?
when you add the button to view, add a tag to button
chatBtn.tag = 1234;
[self.view addSubview:chatBtn];
when you try to hide the button access it's tag
- (void)hideButton
{
UIButton *chatBtn = (UIButton *)[self.view viewWithTag:1234];
[chatBtn setHidden:YES];
}
i have a Navigation Bar, wich contains a Navigation Item, which contains 2 Bar Buttons, these are created in the Storyboard, and i wanted to change 1 of the buttons at runtime, now this works:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
UINavigationItem *thisNavBar = [self myNavigationItem];
thisNavBar.rightBarButtonItem = nil; // this works, it gets removed
UIBarButtonItem *insertBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:#selector(insertSkemaItem:)];
thisNavBar.rightBarButtonItem = insertBtn; // this also works, it sets the btn
}
Now, in my other method, which is called by another controller, it does not work
- (void)callChildChange {
...
// remove old btn
UINavigationItem *thisNavBar = [self skemaNavigationItem];
thisNavBar.rightBarButtonItem = nil; // does not work?
}
There is nothing wrong with the method, it runs just fine, but the nav btn item does not get removed ?
skemaNavigationItem is a Navigation item, declared in the .h file which links the navigation item i made via the storyboard.
Your UI items need to be added to your code (by ctrl-dragging) in the header file (.h) so they can be publicly accessed from other classes/view controllers.
Presuming you've done this, hiding a UI item is best done by using
relevantClass.yourViewObject.hidden = YES;
or if you really need to delete it for good,
[relevantClass.yourViewObject.view removeFromSuperView];
Edits
Options for changing target method:
Declare #property (nonatomic, assign) BOOL myButtonWasPressed; and:
- (IBAction) myButtonPressed
{
if (!self.myButtonWasPressed)
{
// This code will run the first time the button is pressed
self.myButton.text = #"New Button Text";
self.myButtonWasPressed = YES;
}
else
{
// This code will run after the first time your button is pressed
// You can even set your BOOL property back, and make it toggleable
}
}
or
- (IBAction) myButtonWasPressedFirstTime
{
// do what you need to when button is pressed then...
self.myButton.text = #"New Button Text";
[self.myButton removeTarget:self action:#selector(myButtonPressedFirstTime) forControlEvents:UIControlEventTouchUpInside];
[self.myButton addTarget:self action:#selector(myButtonPressedAgain) forControlEvents: UIControlEventTouchUpInside];
}
- (IBAction) myButtonWasPressedAgain
{
// this code will run the subsequent times your button is pressed
}
I have 2 buttons on my view and i want to disable the first button when i click on an other button and disable the second when I click again on the button.
I have tried with this code
if (button1.enable = NO) {
button2.enable = NO;
}
So I have in a NavigationBar a "+" button and 5 disable buttons in my view.
When I push the "+" button I want to enable the first button and when I push again that enable the second…
Thanks
if (button1.enabled == YES)
{
button1.enabled = NO;
button2.enabled = YES;
}
else (button2.enabled == YES)
{
button2.enabled = NO;
button1.enabled = YES;
}
Is that what your looking for? It would be an IBAction for the other button.
button1.enable = YES should be button1.enable == YES
a better readable form: [button1 isEnabled]
You're saying
if (button1.enabled = NO) {
when you probably mean
if (button1.enabled == NO) {
= is the assignment operator, and == is the boolean equality operator. What you're doing at the moment is assigning YES to button1.enable, which obviously enables button1. Then, because button.enable is true, control enters the if's clause and enables button2.
EDIT: To answer your new question ("When I push the "+" button I want to enable the first button and when I push again that enable the second..."), let's say that you initialise the button states somewhere. In your #interface add an instance variable
NSArray *buttons;
so your interface declaration looks something like
#interface YourViewController: UIViewController {
IBOutlet UIButton *button1;
IBOutlet UIButton *button2;
IBOutlet UIButton *button3;
IBOutlet UIButton *button4;
IBOutlet UIButton *button5;
NSArray *buttons;
}
and then initialise buttons like so:
-(void)viewDidLoad {
[super viewDidLoad];
buttons = [NSArray arrayWithObjects: button1, button2, button3, button4, button5, nil];
[buttons retain];
for (UIButton *each in buttons) {
each.enabled = NO;
}
-(void)viewDidUnload {
[buttons release];
[super viewDidUnload];
}
Let's say you hook up the + button's Touch Up Inside event handler to plusPressed:. Then you'd have
-(IBAction)plusPressed: (id) button {
for (UIButton *each in buttons) {
if (!each.enabled) {
each.enabled = YES;
break;
}
}
}
Each time plusPressed: is called, the next button in the array will be enabled. (I'm writing the above away from a compiler; there may be syntax errors.)
You could also make buttons a property. I didn't, because other classes have no business accessing buttons.