I created a toolbar in IB with several buttons. I would like to be able to hide/show one of the buttons depending on the state of the data in the main window.
UIBarButtonItem
doesn't have a hidden property, and any examples I've found so far for hiding them involve setting nav bar buttons to nil, which I don't think I want to do here because I may need to show the button again (not to mention that, if I connect my button to an IBOutlet, if I set that to nil I'm not sure how I'd get it back).
Save your button in a strong outlet (let's call it myButton
) and do this to add/remove it:
// Get the reference to the current toolbar buttons
NSMutableArray *toolbarButtons = [self.toolbarItems mutableCopy];
// This is how you remove the button from the toolbar and animate it
[toolbarButtons removeObject:self.myButton];
[self setToolbarItems:toolbarButtons animated:YES];
// This is how you add the button to the toolbar and animate it
if (![toolbarButtons containsObject:self.myButton]) {
// The following line adds the object to the end of the array.
// If you want to add the button somewhere else, use the `insertObject:atIndex:`
// method instead of the `addObject` method.
[toolbarButtons addObject:self.myButton];
[self setToolbarItems:toolbarButtons animated:YES];
}
Because it is stored in the outlet, you will keep a reference to it even when it isn't on the toolbar.
I know this answer is late for this question. However, it might help if anybody else faces a similar situation.
In iOS 7, to hide a bar button item, we can use the following two techniques :-
use SetTitleTextAttributes :- This works great on bar button items like "Done", "Save" etc. However, it does not work on items like Add, Trash symbol etc.(atleast not for me) since they are not texts.
use TintColor :- If I have a bar button item called "deleteButton" :-
To hide the button, I used the following code:-
[self.deleteButton setEnabled:NO];
[self.deleteButton setTintColor: [UIColor clearColor]];
To show the button again I used the following code:-
[self.deleteButton setEnabled:YES];
[self.deleteButton setTintColor:nil];
deleteButton.enabled = false; deleteButton.tintColor = UIColor.clearColor()
to disable and hide, and deleteButton.enabled = true; deleteButton.tintColor = nil
to re-enable and show as normal.
UIColor.clear
for UIControlState.disabled
and can show/hide the button with setEnabled
. Of course as you stated, this works only for text buttons.
Here's a simple approach:
hide: barbuttonItem.width = 0.01;
show: barbuttonItem.width = 0; //(0 defaults to normal button width, which is the width of the text)
I just ran it on my retina iPad, and .01 is small enough for it to not show up.
self.window?.tintColor = APP_PRIMARY_COLOR
in appdelegate, then this will not work
It is possible to hide a button in place without changing its width or removing it from the bar. If you set the style to plain, remove the title, and disable the button, it will disappear. To restore it, just reverse your changes.
-(void)toggleBarButton:(bool)show
{
if (show) {
btn.style = UIBarButtonItemStyleBordered;
btn.enabled = true;
btn.title = @"MyTitle";
} else {
btn.style = UIBarButtonItemStylePlain;
btn.enabled = false;
btn.title = nil;
}
}
Below is my solution though i was looking it for Navigation Bar.
navBar.topItem.rightBarButtonItem = nil;
Here "navBar" is a IBOutlet to the NavigationBar in the view in XIB Here i wanted to hide the button or show it based on some condition. So i m testing for the condition in "If" and if true i am setting the button to nil in viewDidLoad method of the target view.
This may not be relevant to your problem exactly but something similar incase if you want to hide buttons on NavigationBar
rightBarButtonItem
again, make sure the button item is stored in a strong IBOutlet so that it's not released when you take it off the navigation bar.
For Swift 3 and Swift 4 you can do this to hide the UIBarButtomItem
:
self.deleteButton.isEnabled = false
self.deleteButton.tintColor = UIColor.clear
And to show the UIBarButtonItem
:
self.deleteButton.isEnabled = true
self.deleteButton.tintColor = UIColor.blue
On the tintColor
you must have to specify the origin color you are using for the UIBarButtomItem
I am currently running OS X Yosemite Developer Preview 7 and Xcode 6 beta 6 targeting iOS 7.1 and following solution works fine for me:
Create outlet for UINavigationItemand UIBarButtonItems
Run following code to remove [self.navItem setRightBarButtonItem:nil]; [self.navItem setLeftBarButtonItem:nil];
Run following codes to add buttons again [self.navItem setRightBarButtonItem:deleteItem]; [self.navItem setLeftBarButtonItem:addItem];
I used IBOutlets in my project. So my solution was:
@IBOutlet weak var addBarButton: UIBarButtonItem!
addBarButton.enabled = false
addBarButton.tintColor = UIColor.clearColor()
And when you'll need to show this bar again, just set reversed properties.
In Swift 3 instead enable
use isEnable
property.
self.dismissButton.customView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
iOS 8. UIBarButtonItem with custom image. Tried many different ways, most of them were not helping. Max's solution, thesetTintColor
was not changing to any color. I figured out this one myself, thought it will be of use to some one.
For Hiding:
[self.navigationItem.rightBarButtonItem setEnabled:NO];
[self.navigationItem.rightBarButtonItem setImage:nil];
For Showing:
[self.navigationItem.rightBarButtonItem setEnabled:YES];
[self.navigationItem.rightBarButtonItem setImage:image];
Try in Swift, don't update the tintColor
if you have some design for your UIBarButtonItem like font size in AppDelegate, it will totally change the appearance of your button when showing up.
In case of a text button, changing title can let your button 'disappear'.
if WANT_TO_SHOW {
myBarButtonItem.enabled = true
myBarButtonItem.title = "BUTTON_NAME"
}else{
myBarButtonItem.enabled = false
myBarButtonItem.title = ""
}
I discovered another wrinkle in the tintColor
and isEnabled
approach suggested by Max and others - when VoiceOver is enabled for accessibility and the button is logically hidden, the accessibility cursor will still focus on the bar button, and state that it is "dimmed" (i.e. because isEnabled
is set to false). The approach in the accepted answer doesn't suffer from this side-effect, but another work around I found was to set isAccessibilityElement
to false when "hiding" the button:
deleteButton.tintColor = UIColor.clear
deleteButton.isEnabled = false
deleteButton.isAccessibilityElement = false
And then setting isAccessibilityElement
back to true when "showing" the button:
deleteButton.tintColor = UIColor.blue
deleteButton.isEnabled = true
deleteButton.isAccessibilityElement = true
Having the bar button item still take up space was not an issue in my case, since we were hiding/showing the left-most of right bar button items.
Here is an extension that will handle this.
extension UIBarButtonItem {
var isHidden: Bool {
get {
return tintColor == .clear
}
set {
tintColor = newValue ? .clear : .white //or whatever color you want
isEnabled = !newValue
isAccessibilityElement = !newValue
}
}
}
USAGE:
myBarButtonItem.isHidden = true
@IBDesignable class AttributedBarButtonItem: UIBarButtonItem {
var isHidden: Bool = false {
didSet {
isEnabled = !isHidden
tintColor = isHidden ? UIColor.clear : UIColor.black
}
}
}
And now simply change isHidden
property.
Improving From @lnafziger answer
Save your Barbuttons in a strong outlet and do this to hide/show it:
-(void) hideBarButtonItem :(UIBarButtonItem *)myButton {
// Get the reference to the current toolbar buttons
NSMutableArray *navBarBtns = [self.navigationItem.rightBarButtonItems mutableCopy];
// This is how you remove the button from the toolbar and animate it
[navBarBtns removeObject:myButton];
[self.navigationItem setRightBarButtonItems:navBarBtns animated:YES];
}
-(void) showBarButtonItem :(UIBarButtonItem *)myButton {
// Get the reference to the current toolbar buttons
NSMutableArray *navBarBtns = [self.navigationItem.rightBarButtonItems mutableCopy];
// This is how you add the button to the toolbar and animate it
if (![navBarBtns containsObject:myButton]) {
[navBarBtns addObject:myButton];
[self.navigationItem setRightBarButtonItems:navBarBtns animated:YES];
}
}
When ever required use below Function..
[self showBarButtonItem:self.rightBarBtn1];
[self hideBarButtonItem:self.rightBarBtn1];
Just Set barButton.customView = UIView()
and see the Trick
There is no way to "hide" a UIBarButtonItem you must remove it from the superView and add it back when you want to display it again.
This is long way down the answer list, but just in case somebody wants an easy copy and paste for the swift solution, here it is
func hideToolbarItem(button: UIBarButtonItem, withToolbar toolbar: UIToolbar) {
var toolbarButtons: [UIBarButtonItem] = toolbar.items!
toolbarButtons.removeAtIndex(toolbarButtons.indexOf(button)!)
toolbar.setItems(toolbarButtons, animated: true)
}
func showToolbarItem(button: UIBarButtonItem, inToolbar toolbar: UIToolbar, atIndex index: Int) {
var toolbarButtons: [UIBarButtonItem] = toolbar.items!
if !toolbarButtons.contains(button) {
toolbarButtons.insert(button, atIndex: index)
toolbar.setItems(toolbarButtons, animated:true);
}
}
One way to do it is use the initWithCustomView:(UIView *)
property of when allocating the UIBarButtonItem
. Subclass for UIView
will have hide/unhide property.
For example:
1. Have a UIButton
which you want to hide/unhide.
2. Make the UIButton
as the custom view. Like :
UIButton*myButton=[UIButton buttonWithType:UIButtonTypeRoundedRect];//your button
UIBarButtonItem*yourBarButton=[[UIBarButtonItem alloc] initWithCustomView:myButton];
3. You can hide/unhide the myButton
you've created. [myButton setHidden:YES];
For Swift version, here is the code:
For UINavigationBar
:
self.navigationItem.rightBarButtonItem = nil
self.navigationItem.leftBarButtonItem = nil
Setting the text color to a clear color when the bar button item is disabled is probably a cleaner option. There's no weirdness that you have to explain in a comment. Also you don't destroy the button so you still keep any associated storyboard segues.
[self.navigationItem.rightBarButtonItem setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor clearColor]}
forState:UIControlStateDisabled];
Then when ever you want the bar button item hidden, you can just do:
self.navigationItem.rightBarButton.enabled = NO;
It's lame there's no hidden property but this offers the same result.
In case the UIBarButtonItem has an image instead of the text in it you can do this to hide it: navigationBar.topItem.rightBarButtonItem.customView.alpha = 0.0;
Some helper methods I thought I'd share based upon lnafziger's accepted answer as I have multiple toolbars and multiple buttons in each:
-(void) hideToolbarItem:(UIBarButtonItem*) button inToolbar:(UIToolbar*) toolbar{
NSMutableArray *toolbarButtons = [toolbar.items mutableCopy];
[toolbarButtons removeObject:button];
[toolbar setItems:toolbarButtons animated:NO];
}
-(void) showToolbarItem:(UIBarButtonItem*) button inToolbar:(UIToolbar*) toolbar atIndex:(int) index{
NSMutableArray *toolbarButtons = [toolbar.items mutableCopy];
if (![toolbarButtons containsObject:button]){
[toolbarButtons insertObject:button atIndex:index];
[self setToolbarItems:toolbarButtons animated:YES];
}
}
You can easily get the view and hide it this way
let view: UIView = barButtonItem.valueForKey("view") as! UIView
view.hidden = true
If you are using Swift 3
if (ShowCondition){
self.navigationItem.rightBarButtonItem = self.addAsset_btn
}
else {
self.navigationItem.rightBarButtonItem = nil
}
Complementing Eli Burke`s response, if your UIBarButtonItem
has a background image instead of a title, you can use the code:
-(void)toggleLogoutButton:(bool)show{
if (show) {
self.tabButton.style = UIBarButtonItemStyleBordered;
self.tabButton.enabled = true;
UIImage* imageMap = [UIImage imageNamed:@"btn_img.png"];
[((UIButton *)[self.tabButton customView]) setBackgroundImage:imageMap forState:UIControlStateNormal];
} else {
self.tabButton.style = UIBarButtonItemStylePlain;
self.tabButton.enabled = false;
[((UIButton *)[self.tabButton customView]) setBackgroundImage:nil forState:UIControlStateNormal];
}
}
You can use text attributes to hide a bar button:
barButton.enabled = false
barButton.setTitleTextAttributes([NSForegroundColorAttributeName : UIColor.clearColor()], forState: .Normal)
Also see my solution with UIBarButtonItem extension for the similar question: Make a UIBarButtonItem disapear using swift IOS
You need to manipulate the toolbar.items array.
Here is some code I use to hide and display a Done button. If your button is on the extreme edge of the toolbar or in-between other buttons your other buttons will move, so if you want your button to just disappear then place your button as the last button towards the centre. I animate the button move for effect, I quite like it.
-(void)initLibraryToolbar {
libraryToolbarDocumentManagementEnabled = [NSMutableArray arrayWithCapacity:self.libraryToolbar.items.count];
libraryToolbarDocumentManagementDisabled = [NSMutableArray arrayWithCapacity:self.libraryToolbar.items.count];
[libraryToolbarDocumentManagementEnabled addObjectsFromArray:self.libraryToolbar.items];
[libraryToolbarDocumentManagementDisabled addObjectsFromArray:self.libraryToolbar.items];
trashCan = [libraryToolbarDocumentManagementDisabled objectAtIndex:3];
mail = [libraryToolbarDocumentManagementDisabled objectAtIndex:5];
[libraryToolbarDocumentManagementDisabled removeObjectAtIndex:1];
trashCan.enabled = NO;
mail.enabled = NO;
[self.libraryToolbar setItems:libraryToolbarDocumentManagementDisabled animated:NO];
}
so now can use the following code to show your button
[self.libraryToolbar setItems:libraryToolbarDocumentManagementEnabled animated:YES];
trashCan.enabled = YES;
mail.enabled = YES;
or to hide your button
[self.libraryToolbar setItems:libraryToolbarDocumentManagementDisabled animated:YES];
trashCan.enabled = NO;
mail.enabled = NO;
In IB if you leave the button's title blank it will not appear (never initialized?). I do this often during development during UI updates if I want a bar button item to temp disappear for a build without deleting it and trashing all its outlet references.
This does not have the same effect during runtime, setting the button's title to nil will not cause it the whole button to disappear. Sorry doesn't really answer your question, but may be useful to some.
Edit: This trick only works if the button's style is set to plain
I'll add my solution here as I couldn't find it mentioned here yet. I have a dynamic button whose image depends on the state of one control. The most simple solution for me was to set the image to nil
if the control was not present. The image was updated each time the control updated and thus, this was optimal for me. Just to be sure I also set the enabled
to NO
.
Setting the width to a minimal value did not work on iOS 7.
Success story sharing