I would like to dynamically hide a button in one of my views depending on a certain condition.
I tried adding some code to the view controller's -viewWillAppear method, to make the button hidden before displaying the actual view, but I still don't know how to do that.
I have a reference to the button through an IBOutlet, but I'm not sure how to move forward from here. For reference, this is a UIBarButtonItem instance.
If you're trying to hide a UIBarButtonItem, you'll actually have to modify the contents of the parent bar. If it's a UIToolBar, you'll need to set the bar's items array to an array that doesn't include your item.
NSMutableArray *items = [[myToolbar.items mutableCopy] autorelease];
[items removeObject: myButton];
myToolbar.items = items;
Set the bar item to nil.
For example:
self.navigationItem.leftBarButtonItem = nil;
So I tried Ben's winning approach but in the end I found it to be wrong for my purposes - though I'm sure it depends upon what you're trying to do. I was trying to show a nav bar button under certain conditions only and then hide it as soon as the condition was no longer met (in my case it's a "Done" button used to hide the keyboard associated with a UITextView. It should only be displayed when the user is typing in the text view). My steps were as follows:
I added a UIBarButtonItem as a
property in my UIViewController
class. I instantiate it in the
initWithNibName method.
I assigned the UIBarButtonItem property as the
rightBarButtonItem in the nav bar as
soon as the user starts typing in
the text view.
I set the UIBarButtonItem property
to nil when the user is done typing.
It's working like a charm. I'm adding some code samples below.
First to instantiate the button in my view controller init method:
barButtonItemDone = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(done:)];
Then I set it as the right bar button in the delegate method that is called as soon as the user starts to edit the text view:
self.navigationItem.rightBarButtonItem=[self barButtonItemDone];
Finally, when the button itself is clicked, a method called "done" is called and I just set the rightBarButtonItem to nil inside that method:
self.navigationItem.rightBarButtonItem=nil;
If all that one is trying to hide is the back button in the navigation bar, there is an easier way:
self.navigationItem.hidesBackButton = YES;
Quote from developer documentation:
hidesBackButton
A Boolean value that determines whether the back button is hidden.
#property(nonatomic, assign) BOOL hidesBackButton
Discussion
YES if the back button is hidden when this navigation item is the top
item; otherwise, NO. The default value
is NO.
Availability
Available in iPhone OS 2.0 and later.
This is a bit of a hack, but it works in my case (and it properly handles dynamic spacing):
To hide:
myButton.width = 0.1;
To show:
myButton.width = 0.0;
A width of 0.0 is "auto width", and with a width of 0.1, the button totally disappears (not even a "sliver" of a button, though I haven't tried this on a retina display).
Another hacky solution:
myButton.customView = [[UIView alloc] init];
The best solution to this is less technical. All you need to do is create your normal navigation bar (top) or toolbar (bottom), but without the optional button. Then create another identical, but shorter bar which you then place at the part you want the optional button and create your optional button on this second shorter bar.
Now you can call hidden = YES on the whole additional bar.
The bars seamlessly overlap for me, your mileage may vary.
This answer is regarding text-based UIBarButtonItems, however, the same concept could be applied to other types of buttons as well. Note that this will allow one to both hide and show the item again. Many of the answers above (those setting the button's value to nil, for example, do not allow the button to be re-shown if that's desired).
TL;DR:
if (shouldShowMyBarButtonItem) {
self.myBarButtonItem.title = nil;
self.myBarButtonItem.action = nil;
} else if (!shouldShowMyBarButtonItem) {
self.myBarButtonItem.title = #"Title";
self.myBarButtonItem.action = #selector(mySelector:);
}
The long version:
The UIBarButtonItem I was trying to hide is in a UIToolbar, not a UINavigationBar so all the suggestions that access the left (or right) barButtonItem properties on the navigation item don't work for me. Also, as stated above, I wished to re-show the button when circumstances change.
Michael's suggestion came closest to working, however, with iOS 7 at least, there was still a very small sliver of the button displayed that was tappable. In my app, tapping the item when it's not supposed to be available was unacceptable. The above code both hides and, crucially, deactivates the button.
I call the above code in a private refresh method, which is called when a user event occurs.
This is what I did for button items that weren't part of the navigation bar (where Blank.png is a blank image I created that's the same size of the image it replaces):
theButton.enabled = NO;
theButton.image = [UIImage imageNamed: #"Blank.png"];
Ben's answer is technically correct, though when I try it on my custom UIToolbar, the items space out in a way that I don't like, because I use UIBarButtonSystemItemFlexibleSpace items.
If you want your other items to stay in the same place, you'll either have to set your flexible spaces to fixed spaces, or try what I did:
[filterBarButton.customView setHidden:YES];
note: this only works if your UIBarButtonItem uses custom views.
If you add a UIButton to the UIBarButtonItem rather than just use the UIBarButtonItem.
You can then assign UIButton.hidden to TRUE or YES and it (and the UIBarButtonItem) will not be visible or active.
Hope that helps.
Just set the button's hidden property to true:
myButton.hidden = YES;
Related
I have two UIButtons that I added to my view
[self.view addSubview:button1];
[self.view addSubview:button2];
These buttons have a selector and in the selector is a menu where the user can choose an option and this option can vary in string size for the button so I decided to remove the buttons from the view and reload them again with different string size and button size. I have am getting the information from an API call so there is where I set the buttons up to my view. I tried to do this:
[button1 removeFromSuperview];
Also tried:
[self.button1 removeFromSuperView];
Now, for the UILabel I have it inside a table view cell because the string is long and covers my detailTextLabel. I am using UITableViewCellStyleValue1 for the cells. I have tried to use NSLineBreakByWordWrapping and set the numberOfLines to 0 as well as 5 so I then decided to add the UILabel inside the table view cell so I can control how far the string goes and I can also wrap that around. Since the cell was writing over and over the label every time the cell with the table view was hidden, I decided to create the label inside the if(cell == nil) statement.Like the button, this label also gets refreshed when the buttons are pressed and a menu option is chosen so I have to remove it from the view, the same way i did the buttons. For some reason it isn't working. Anyone have any thoughts/ideas/suggestions?
I also NSLog(#"%#",[button1 superview]) after I removed it to make sure that the button was indeed (null) as well as the label, and they do show up on the terminal as null but the buttons overlap each other, in fact you can still click the old button and you can see it underneath the new button. Same goes with the label. If you need any code let me know, this problem is frustrating me so much!
Also, I am on iOS7 and for some reason my device isn't displaying the status bar. I've tried to change it inside the info.plist -> status bar style. I've tried the 3 options it has but none of them seem to work. I checked all my xib files and checked for any hidden keywords in my .m files. Thanks in advance.
Since you mentioned the button was making an API call I am guessing you may be threading that section of code. If that's the case then the reason its not working is likely because you are not allowed to update the UI in a background thread.
Try replacing:
[button1 removeFromSuperview];
with this:
[button1 performSelectorOnMainThread:#selector(removeFromSuperview) withObject:nil waitUntilDone:NO];
I deeply suggest using storyboards, they make working with the UI a lot easier! They also allow you to play with constraints to see how your UI elements react to longer text or to the screen rotating, etc...
That apple tutorial:
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/SecondiOSAppTutorial/Introduction/Introduction.html
goes through a simple app with storyboards!
I have a toolbar with 5 buttons.
4 of them are regular bar button items and one of them is a custom one (A 'UIButton' inside a 'UIBarButtonItem').
I noticed that when I click between the regular buttons (not exactly on them), one of them (the closest one) still recieves the click event and is being highlighted (which is what I want).
But the custom bar button item does not show this behaviour.
When I tap between it and one of the regular buttons neither of the 2 receives the touch event. This probably because the UIButton is the one the gets the click event. Is there a way to add a touch event the containing bar button item as well? Or perhaps another way to solve this?
Thanks!
button.userInteractionEnabled = YES; I believe is the answer.
One solution might be that you create image of same as bar button item and assign to UIButton as background image, this will solve your issue.
Hope this helps you....
Solved it!
I added another UIView to the UIBarButtonItem and then I added the UIButton to the UIView.
I added a touch gesture to the UIView (And also kept the original touch event of the UIButton) that expanded the area that you can touch the button which solved the problem.
In IB I can set the identifier of a UIBarButtonItem to 'play' which adds an image of a play button (right-pointing triangle).
Is there a way to change this image programmatically? I want to change it to 'pause' when the play button is pressed.
I know you can initialize a UIBarButtonItem with an identifier but I've yet to find a way to change it after it's been initialized. Is this even possible?
The only thing I can think of is to remove the old button and initialize a new one in its place, but this hardly seems efficient.
Any thoughts?
Ok I've googled this question to death and ran into sample code from Apple where they do exactly the same thing (toggle play/pause button graphic on a toolbar button). But instead of using the built in play and pause identifiers of UIBarButtonItem they use a custom UIButton and toggle custom images.
So if Apple goes through the trouble of creating and toggling custom images on a UIButton instead of the built in play and pause UIBarButtonItem buttons then I think it's pretty safe to say there's no way to programatically change the identifier of a UIBarButtonItem.
This is what they (Apple) do to toggle the images when the button is pressed:
// Call this when the button you want to toggle is pressed:
[playButton setImage:((p.playing == YES) ? pauseBtnBG : playBtnBG) forState:UIControlStateNormal];
Replace p.playing with whatever BOOL you want to hold the state of your button. playButton is the custom UIButton in the toolbar. pauseBtnBG and playBtnBG are the images to toggle.
This seems to work fairly well:
UIBarButtonItem *oldButton = [myToolBar.items objectAtIndex:1];
[myToolBar setItems:[NSArray arrayWithObjects:[myToolBar objectAtIndex:0], [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemStop target:self action:#selector(tapStopRefreshButton:)],nil] animated:NO];
[oldButton release];
In this example I had a toolbar for a UIWebView and when someone clicked Reload I wanted it to change to Stop. The toolbar only had a flexible space and the one button on it - to right-align the button - so I grabbed a reference to the old button, made a new one with the same selector as the old, reset the buttons on the tab bar, and then released the original button.
Not the prettiest, but you can use all standard buttons without having to override the button class(es).
What about 2 stacked toolbars? Then you can have some system buttons in the top one, and others in the bottom one. If the play button is pressed, then just hide the top toolbar.
I have a UITableViewController where I added a "editButtonItem" in the navigation bar :
self.navigationItem.leftBarButtonItem = self.editButtonItem;
No magic here, but I try to define the color (background and foreground/textcolor) of this button.
I read in the Apple forum somewhere that the button changes the color if I change the navigationbar to the same color, well despite the fact that I do not get this to work either (for testing) I do not want to touch the navigationbr itself, just the button.
Since this button is already predefined I am not sure how to handle this. Do I need to overwrite the button with my own definition or can I just simply apply a new style (if so how ?)
Thx
If everything fails, you can tint the bar in the viewDidLoad of your childViewController
[self.navigationController.navigationBar setTintColor:[UIColor colorWithHue:50 saturation:50 brightness:.2 alpha:.5]];
The only way I can find to make a UIBarButtonItem with a different color is to use a custom view and the initWithCustomView: method. Predefined buttons and those created using initWithTitle:target:action: cannot change their background color.
Take a look at this SO question: UIBarButtonItem with color?
These links might also help:
http://www.iphonedevsdk.com/...
http://www.insanelymac.com/...
Trying to move the position of the back item on the UINavigationBar by getting a handle to the backbutton however I only seem to be able to make it disappear rather than do anything with it
I have the following in viewDidLoad
self.navigationItem.leftBarButtonItem.title =#"Testing";
self.navigationItem.backBarButtonItem.title= #"1234";
They do not work however
self.navigationItem.hidesBackButton = YES;
Works as you would expect, looking through the documentation it looks like higher up the backItem might be readonly is this the case?
self.navigationController.navigationBar.backItem; // readonly
Any pointers on how to move this in approx 30 pixels much appreciated!
I don't believe this is possible. However, you can define a custom button (with back functionality) and place it wherever you want on the nav bar. Then simply hide the back button