273

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).

Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358
Sasha
  • 3,405
  • 4
  • 19
  • 21
  • I simply disabled it and added a accessibility label saying the button's feature is not available. –  Nov 01 '19 at 01:24

39 Answers39

271

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.

lnafziger
  • 25,760
  • 8
  • 60
  • 101
  • 75
    To make this work for my right button in a Navigation controller I used self.navigationItem.rightBarButtonItems and [self.navigationItem setRightBarButtonItems] instead of toolBarItems and setToolBarItems. – MindSpiker Nov 12 '12 at 19:11
  • 1
    @MindSpiker: Yes, he same technique works for the buttons on a navigation bar as well. – lnafziger Nov 12 '12 at 19:43
  • 1
    do i have to nil myButton in dealloc? – Van Du Tran Oct 05 '13 at 14:27
227

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];
Max
  • 4,067
  • 1
  • 18
  • 29
  • [self.navigationItem.rightBarButtonItem setEnabled:NO]; [self.navigationItem.rightBarButtonItem setTintColor: [UIColor clearColor]]; – Leon Jul 02 '15 at 21:02
  • 5
    For Swift: `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. – Unixmonkey Jul 08 '15 at 22:04
  • 1
    I like that this approach lets me put the logic for whether or not to display the UIBarButton inside that class. The reason it only works with one button is not immediately obvious--it's because if you hide a button this way it will still take up space, so you might have an empty gap if you have multiple buttons. – SimplGy Nov 15 '16 at 19:54
  • Your first approach was perfect for me. I set `UIColor.clear` for `UIControlState.disabled` and can show/hide the button with `setEnabled`. Of course as you stated, this works only for text buttons. – heyfrank Sep 11 '18 at 15:18
  • If l long press on it until it pops up in a big image (probably for accessibility) then even with isEnabled set to false it still works. –  Dec 30 '18 at 23:31
67

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.

kbpontius
  • 3,867
  • 1
  • 30
  • 34
Drew Rosenberg
  • 899
  • 6
  • 7
  • 13
    Of all the solutions, this one was quick, dirty, and effective. I also added barbuttItem.enabled = NO; since I could still get the button to fire if I hit it enough. – Stickley Sep 26 '12 at 20:52
  • 1
    Doesn't work for me. I thought it was because I was using an Add button with the '+' image, but I tried a Custom button with the text "New" instead and it still doesn't vanish. The enablement changes so I know my code is being executed. Any ideas? Note that this button is created in a storyboard and has a segue so I dont want to change to a programmatic button instead – Rhubarb Oct 01 '12 at 16:56
  • 23
    It doesn't seem to work in a navigation controller toolbar, but it does for other toolbars. – Drew Rosenberg Oct 02 '12 at 19:23
  • 3
    It hides it but it still responds to taps. For me it acts like an invisible button. – Tibidabo Jul 24 '13 at 13:59
  • If you have set global tint color by using this line `self.window?.tintColor = APP_PRIMARY_COLOR` in appdelegate, then this will not work – Mehul Thakkar Jun 19 '17 at 05:46
62

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;
    }
}
Eli Burke
  • 2,729
  • 27
  • 25
  • 2
    This worked for me by simply setting btn.title = nil. I'm also setting enabled = NO, just in case... – Pork 'n' Bunny Aug 07 '13 at 15:18
  • 3
    Setting the buttonItem.title to nil didn't work for me in iOS7. The button did not reappear when setting it back. However what did work was setting buttonItem.title=@" "; – Mark Knopper Oct 01 '13 at 13:23
44

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

vishal dharankar
  • 7,536
  • 7
  • 57
  • 93
  • If you want to later set `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. – Nate Oct 22 '16 at 12:01
36

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

pableiros
  • 14,932
  • 12
  • 99
  • 105
22

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];
    
Olcay Ertaş
  • 5,987
  • 8
  • 76
  • 112
  • 1
    Thanks, this is the best method I've found as well. Just make sure your references to your buttons are strong. – jyoung Jul 27 '15 at 03:50
  • 1
    Also, keep in mind that this works only if you have just one button there. The example will remove ALL buttons on that side. – lnafziger Nov 14 '15 at 16:54
  • @jyoung This worked for me, but why does it matter if the reference is strong? I didn't try the other way, but usually don't set it that way since it's not the default. – Robert Nov 17 '15 at 01:52
  • 1
    @Robert You want to use the object at a later time, so you need to make sure the object doesn't get garbage collected when you set it to nil. If nothing else was retaining the object when you told the bar button item it's ok to get rid of it, it's reference count would be 0 and it would be garbage collected. – jyoung Nov 18 '15 at 16:27
14

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.

Den
  • 1,456
  • 16
  • 17
13

self.dismissButton.customView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];

Vyacheslav
  • 26,359
  • 19
  • 112
  • 194
Dmitry Semenyuk
  • 3,459
  • 1
  • 17
  • 12
12

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];
Rinto Rapheal
  • 142
  • 1
  • 10
10

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.

Evan Kirkwood
  • 418
  • 4
  • 14
9

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 = ""
}
Jeffrey Neo
  • 3,693
  • 2
  • 26
  • 30
7

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
Elijah
  • 8,381
  • 2
  • 55
  • 49
6
@IBDesignable class AttributedBarButtonItem: UIBarButtonItem {

    var isHidden: Bool = false {

        didSet {

            isEnabled = !isHidden
            tintColor = isHidden ? UIColor.clear : UIColor.black
        }
    }
}

And now simply change isHidden property.

Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358
5

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];
delavega66
  • 855
  • 2
  • 23
  • 39
umakanta
  • 1,051
  • 19
  • 25
5

Just Set barButton.customView = UIView() and see the Trick

Anton
  • 3,102
  • 2
  • 28
  • 47
jeff ayan
  • 819
  • 1
  • 13
  • 16
  • What this answer does do, is allow all the flexible sizing to work. It's actually a super efficient answer. Probably coupled with an extension it would be perfect. – Adrian_H Sep 12 '18 at 14:20
4

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.

Kyle Richter
  • 450
  • 2
  • 6
  • This is actually not true - the method described by Max works well. – northernman Oct 21 '14 at 03:14
  • 1
    nothernman - Max is not actually correct. He isn't actually hiding the button in the way most people would define "hiding". He is simply making it not visible and disabling user interaction. The button is still there and takes up space. It comes down to how you want to define "hide", I believe the spirit of the original question was wanting to actually remove/add it, not just make it invisible. – Michael Peterson Aug 07 '15 at 19:52
4

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);
    }
}
maninvan
  • 890
  • 9
  • 10
  • Not bad but you must give a UINavigationItem as parameter and not UIToolbar because he asks to hide a UIBarButtonItem. I modified your function to this: func hideToolbarItem(button: UIBarButtonItem, withToolbar toolbar: UINavigationItem) { var toolbarButtons: [UIBarButtonItem] = toolbar.rightBarButtonItems! toolbarButtons.removeAtIndex(toolbarButtons.indexOf(button)!) toolbar.setRightBarButtonItems(toolbarButtons, animated: true) } and that works great – Kingalione Apr 08 '16 at 14:09
3

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 UIButtonas 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];

iNoob
  • 3,364
  • 2
  • 26
  • 33
  • However, it won't close the gap between the other buttons: When it is "hidden" there will be an empty area on the toolbar. – lnafziger Apr 05 '12 at 03:29
  • @lnafziger Yes that is true, but i didn't read the OP mention about closing the gap between the buttons, but it is a good point to note though. – iNoob Apr 05 '12 at 03:32
  • 1
    Thanks, your answer is useful too, but I think that most people when they want to hide a button on a toolbar want it to look like it isn't there at all (without the blank area). If it's the left or right one it wouldn't really matter though. – lnafziger Apr 05 '12 at 03:36
  • Good points, iNoob and Inafziger - I didn't mention it either way but yes, I would prefer that there not be a blank spot. – Sasha Apr 06 '12 at 01:33
3

For Swift version, here is the code:

For UINavigationBar:

self.navigationItem.rightBarButtonItem = nil

self.navigationItem.leftBarButtonItem = nil
Sohil R. Memon
  • 9,404
  • 1
  • 31
  • 57
2

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.

puppybits
  • 1,110
  • 12
  • 16
  • 1
    I had a button inside the rightBarButtonItem. So I set its enabled to NO and changed its image on disabled state to nil. Worked like a charm...Thanks – Skywalker Dec 10 '15 at 13:55
  • excellent idea, however setting the image to null didnt work for me, i had to put a little transparent square of 20x20 as the image – Lena Bru Dec 23 '15 at 15:03
2

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;

Artem Goryaev
  • 209
  • 3
  • 3
2

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];
    }
}
Guy Lowe
  • 2,115
  • 1
  • 27
  • 37
2

You can easily get the view and hide it this way

let view: UIView = barButtonItem.valueForKey("view") as! UIView
view.hidden = true
Titouan de Bailleul
  • 12,920
  • 11
  • 66
  • 121
2

If you are using Swift 3

if (ShowCondition){
   self.navigationItem.rightBarButtonItem = self.addAsset_btn 
 } 
else {
   self.navigationItem.rightBarButtonItem = nil
 }
Museer Ahamad Ansari
  • 5,414
  • 3
  • 39
  • 45
2

Finally, from iOS 16+, the UIBarButtonItem has the isHidden property.

So, to expand on the existing answers, something like

extension UIBarButtonItem {
    func show() {
        if #available(iOS 16.0, *) {
            isHidden = false
        } else {
            isEnabled = true
            tintColor = .white
        }
    }
    
    func hide() {
        if #available(iOS 16.0, *) {
            isHidden = true
        } else {
            isEnabled = false
            tintColor = .clear
        }
    }
}
haste
  • 332
  • 1
  • 9
1

Complementing Eli Burke`s response, if your UIBarButtonItemhas 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];
    }
}
Renato Lochetti
  • 4,558
  • 3
  • 32
  • 49
1

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

Community
  • 1
  • 1
iUrii
  • 11,742
  • 1
  • 33
  • 48
0

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;
Graham
  • 151
  • 1
  • 5
0

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

pretzels1337
  • 355
  • 3
  • 10
0

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.

mkko
  • 4,262
  • 3
  • 25
  • 29
0

With credit to @lnafziger, @MindSpiker, @vishal, et. al,

The simplest one liner that I arrived at for a single right (or left) bar button is:

self.navigationItem.rightBarButtonItem = <#StateExpression#>
    ? <#StrongPropertyButton#> : nil;

As in:

@interface MyClass()

@property (strong, nonatomic) IBOutlet UIBarButtonItem *<#StrongPropertyButton#>;

@end

@implementation

- (void) updateState
{
    self.navigationItem.rightBarButtonItem = <#StateExpression#>
        ? <#StrongPropertyButton#> : nil;
}

@end

I tested this and it works for me (with the strong bar button item wired via IB).

Chris Conover
  • 8,889
  • 5
  • 52
  • 68
  • This will work if you only have one button, but if you have multiple buttons you will need to use a method more along the lines of my answer. – lnafziger Apr 26 '14 at 16:20
0

Subclass UIBarButtonItem. Make sure the button in Interface Builder is set to HidableBarButtonItem. Make an outlet from the button to the view controller. From the view controller you can then hide/show the button by calling setHidden:

HidableBarButtonItem.h

#import <UIKit/UIKit.h>

@interface HidableBarButtonItem : UIBarButtonItem

@property (nonatomic) BOOL hidden;

@end

HidableBarButtonItem.m

#import "HidableBarButtonItem.h"

@implementation HidableBarButtonItem

- (void)setHidden:(BOOL const)hidden {
    _hidden = hidden;

    self.enabled = hidden ? YES : NO;
    self.tintColor = hidden ? [UIApplication sharedApplication].keyWindow.tintColor : [UIColor clearColor];
}

@end
Pétur Ingi Egilsson
  • 4,368
  • 5
  • 44
  • 72
0

I worked with xib and with UIToolbar. BarButtonItem was created in xib file. I created IBOutlet for BarButtonItem. And I used this code to hide my BarButtonItem

 self.myBarButtonItem.enabled = NO;
 self.myBarButtonItem.title =  nil;

this helped me.

Kiryl Bielašeŭski
  • 2,663
  • 2
  • 28
  • 40
0

for hiding one of many items, I used the following code:

self.navigationItem.leftBarButtonItems?.remove(at: 0)  
self.navigationItem.rightBarButtonItems?.remove(at: 1)

I guess the items can be re-added if needed.

Atara
  • 3,523
  • 6
  • 37
  • 56
0

I had the problem that I had 2 leftBarButtonItems. On Mac Catalyst firstButton was pointing to an action that was not supported: recording a video with AVFoundation. Only the second button was valid on Mac Catalyst: use an UIImagePickerController.

So on Mac Catalyst I had to point the first UIBarButtonItem to secondButton and always hide the second UIBarButtonItem. On iOS both buttons should be shown. This was my solution:

#if TARGET_OS_MACCATALYST
        self.navigationItem.leftBarButtonItem = self.secondButton;
        NSUInteger count = [self.navigationItem.leftBarButtonItems count];
        for (NSUInteger i = 0; i < count; i++) {
            UIBarButtonItem *thisButton = [self.navigationItem.leftBarButtonItems objectAtIndex:i];
            if (i == 1) {
                thisButton.enabled = NO;
                thisButton.tintColor = [UIColor clearColor];
            }
        }
#else
        self.navigationItem.leftBarButtonItem = self.firstButton;
#endif

I hope it helps someone with a comparable problem.

Jan Ehrhardt
  • 395
  • 1
  • 8
  • 20
0

Reference answer of @haste

extension UIBarButtonItem {
    var isHidden: Bool {
        set {
            if #available(iOS 16.0, *) {
                isHidden = newValue
            } else {
                isEnabled = !newValue
                tintColor = newValue ? .clear : nil
            }
        }
        
        get {
            if #available(iOS 16.0, *) {
                return isHidden
            } else {
                return isEnabled == false && tintColor == .clear
            }
        }
    }
}
yycking
  • 1,017
  • 1
  • 9
  • 14
-1

My answer is here for Swift 4!

if $0 {
    self.navigationItem.rightBarButtonItems = [UIBarButtonItem(customView: self.button1)]
} else {
    self.navigationItem.rightBarButtonItems = [UIBarButtonItem(customView: self.button2)]
}
-5

My solution is set bounds.width to 0 for what you have inside UIBarButtonItem (I used this approach with UIButton and UISearchBar):

Hide:

self.btnXXX.bounds = CGRectMake(0,0,0,0);

Show:

self.btnXXX.bounds = CGRectMake(0,0,40,30); // <-- put your sizes here
Mike Keskinov
  • 11,614
  • 6
  • 59
  • 87