Hiding UINavigationItem's bar button - iphone

I have added a BarButton item to the left of the nav.bar through Interface Builder and in the code I want this only to show in my table view's edit mode. But I didn't find any hidden property to set the leftBarButtonItem (like: self.navigationItem.leftBarButtonItem.hidden = YES).
I can only set enabled property. Anybody know how to control the hide and show property of the leftBarButtonItem, please help.

This works I tried it myself
self.navigationItem.leftBarButtonItem = nil;
self.navigationItem.hidesBackButton = YES;

I'm pretty sure the only way to "hide" it is to nil it out.
self.navigationItem.leftBarButtonItem = nil;
Though it's not a perfect answer to your question, since that basically gets rid of your button instead of hiding it. You'll either have to recreate it or keep your original button around and simply set the leftBarButtonItem back to your UIBarButtonItem.

I have a easy function to make this.
I have a navigation like this.
It comes form Interface Builder, it has a background image.
#IBOutlet weak var memberBtn: UIBarButtonItem!
you can hide/show it by:
func hideMemberBtn() {
memberBtn.isEnabled = false
memberBtn.tintColor = UIColor.clear
}
func showMemberBtn() {
memberBtn.isEnabled = true
memberBtn.tintColor = UIColor.white
}
It's easy but it work for me. You can change tintColor as you needed.
Hope for help :]

You can use
// Hide
self.navigationItem.leftBarButtonItem = nil;
// Show
self.navigationItem.leftBarButtonItem = self.myBarButtonItem
The key is making sure that you have a strong reference to the button item before nilling leftBarButtonItem.
#property (strong, nonatomic) IBOutlet UIBarButtonItem *myBarButtonItem;

I just created my own "hide" function show below:
- (void)hideClearButton:(BOOL)hide {
if (hide) {
self.navigationItem.leftBarButtonItem = nil;
}
else {
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]
initWithTitle:NSLocalizedString(#"Clear", #"Recents")
style:UIBarButtonItemStylePlain
target:self action:#selector(clearAll:)];
}
}
You can just call it like:
[self hideClearButton:YES]; //hide it
or
[self hideClearButton:NO]; //show it

There's nothing in the documentation to suggest bar items have a hidden property.
Why not set
self.navigationItem.leftBarButtonItem = nil;
when the user isn't editing, then set
self.navigationItem.leftBarButtonItem = whateverBarButtonItem;
when the user is editing? This requires either re-creating the button each time or storing it for the duration of the view's lifecycle. Neither is terribly painful, but no, not nearly as easy as a .hidden property.

You can use
[self.navigationItem.leftBarButtonItem setEnabled:TRUE];
as there is no other way to hide it. so just disable it.

To hide/disable
[self.navigationItem.leftBarButtonItem setEnabled:FALSE];
To show/enable
[self.navigationItem.leftBarButtonItem setEnabled:TRUE];

Well making it nil was not a option because i wanted to show it again and didnt want to create a button again.
so what i did was
UIBarButtonItem *barButton = (UIBarButtonItem *)self.navBar.topItem.leftBarButtonItem;
barButton.customView.hidden = true;//Hide
barButton.customView.hidden = false;//Show
Works for me. (my leftBarButtonItem was created using customView)
Hope it helps.

This solution work for me
UIView *myView = [[UIView alloc] initWithFrame: CGRectMake(0, 0, 300, 30)];
UIBarButtonItem *btnL = [[UIBarButtonItem alloc]initWithCustomView:myView];
self.navigationItem.leftBarButtonItem = btnL;

func showOrHideButton() {
isEnabled ? showButton() : hideButton()
}
func showButton() {
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .compose, target: self, action: #selector(action))
}
func hideButton() {
navigationItem.leftBarButtonItem = nil
}

Related

iOS: Navigation bar item disappearing and reappearing

Trying to add and remove navigation Bar Items on the navigation bar, some bar items disappear.
When I run the codes below at viewDidLoad, they work fine.
-(void) resetNavigationBarRearrangeMode {
NSArray*rightBarItems = [[NSArray alloc] initWithObjects:actionCancel, actionSave, actionAddItem, actionRearrange, nil];
self.navBar.topItem.rightBarButtonItems = rightBarItems;
}
When I try to remove some of the bar button items, it appears fine.
- (IBAction)cancelClicked:(id)sender {
NSArray*rightBarItems = [[NSArray alloc] initWithObjects:actionRearrange, nil];
self.navBar.topItem.rightBarButtonItems = rightBarItems;
Log(#"running cancel");
}
But when I clicked rearrange to run the below code, this doesn't work.
- (IBAction)rearrangeClicked:(id)sender {
[self resetNavigationBarRearrangeMode];
}
Anyone know what's wrong? thanks in advance.
The barButtonItems are overlapped each and every time you call the method. You need to reset the barButtonItems by setting it as nil before calling the method for rearranging.
- (IBAction)rearrangeClicked:(id)sender {
self.navigationItem.rightBarButtonItem = nil;
[self resetNavigationBarRearrangeMode];
}
It would work. Refer this link for further assistance.

UIButton buttonWithType:101, Will they reject my app?

Greetings,
In one of my projects I wanted to create back type button(with pointer) in the navigation bar, I googled around and found that using the following code, it can be achieved.
UIButton *someButton = [UIButton buttonWithType:101];
UIBarButtonItem *someBarButton = [[UIBarButtonItem alloc] initWithCustomView:someButton];
I want to upload this app on Apple's app store.
Is there any chance that this will get my app rejected, since buttonWithType:101 is not documented any where?
Also i m not using this bar button item in its generic way, i.e. it wont pop the view controller.
Please guide.
Regards,
I propose that you generate Image for your need, just by running this code and delete it after you generate the image:
- (void)viewDidLoad {
...
someButton = [UIButton buttonWithType:101];
UIBarButtonItem *someBarButton = [[UIBarButtonItem alloc] initWithCustomView:someButton];
self.navigationItem.leftBarButtonItem = someBarButton;
...
}
and
- (void)viewWillAppear:(BOOL)animated {
....
UIImage *img1 = [someButton backgroundImageForState:UIControlStateNormal];
NSData *newData = UIImagePNGRepresentation(img1);
NSFileManager *fileManager =[NSFileManager defaultManager];
BOOL filecreationSuccess = [fileManager createFileAtPath:#"/Users/macbookmac/Desktop/tester.png" contents:newData attributes:nil];
...
}
most probably yes.. in some cases, few things do slip under the radar, but why take chances..
if you are doing this for your client/company, would you risk having a rejection from app store on your hands..
its safer to create a pointed button image and use it with custom button...
If you are trying to control what text appears in the Navigation controller's back button, you can do that with the UIViewController's UINavigationItem. It can contain both the title for the current view and the text to use for the next view's "back" button. This can be set in XIB as well.

How to get keyboard with Next, Previous and Done Button?

I want to have a keyboard which has a Next,Previous and Done button on top of it.
I have seen that in many apps.
Especially where there are forms to be filled.
I want to achieve something similar to above keyboard
How can I get that?
You'll find the answer on this other post.
I checked the iOS Library and the inputAccessoryView of a UITextField is exactly what you're looking for !
Hope this helps !
I just created a class called BSKeyboardControls which makes it very easy to add the controls to a keyboard. The class, instructions and example code can be found here at GitHub.
The controls works for text fields and text views and are optimized for both iPhone and iPad.
-(BOOL)textFieldShouldBeginEditing: (UITextField *)textField
{
UIToolbar * keyboardToolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
keyboardToolBar.barStyle = UIBarStyleDefault;
[keyboardToolBar setItems: [NSArray arrayWithObjects:
[[UIBarButtonItem alloc]initWithTitle:#"Previous" style:UIBarButtonItemStyleBordered target:self action:#selector(previousTextField)],
[[UIBarButtonItem alloc] initWithTitle:#"Next" style:UIBarButtonItemStyleBordered target:self action:#selector(nextTextField)],
[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
[[UIBarButtonItem alloc]initWithTitle:#"Done" style:UIBarButtonItemStyleDone target:self action:#selector(resignKeyboard)],
nil]];
textField.inputAccessoryView = keyboardToolBar;
}
- (void)nextTextField {
if (textField1) {
[textField1 resignFirstResponder];
[textField2 becomeFirstResponder];
}
}
-(void)previousTextField
{
if (textField2) {
[textField2 resignFirstResponder];
[textField1 becomeFirstResponder];
}
}
-(void)resignKeyboard {
[textField1 resignFirstResponder];
[textField2 resignFirstResponder];
}
I have a utility class that basically does this for you.
https://github.com/kalvish21/CustomKeyboard
The idea is very simple. You have to add an accessory tool bar with bar button items on it. There's a delegate which defines where what that button will do.
https://github.com/hackiftekhar/IQKeyboardManager
This is the best keyboard handler I have seen so far. Very excellent way to manage Text inputs.
Some of its features
1) ZERO LINE OF CODE
2) Works Automatically
3) No More UIScrollView
4) No More Subclasses
5) No More Manual Work
6) No More #imports
This is a custom control which is placed directly above the keyboard. I think a UIToolbar can be used for that.
Previous and next passes around the firstResponder of the textFields and Done will do the resign as well as hide the toolbar.
To match the keyboard animation have a look at this code I found or at SO: "What is the iPhone's default keyboard animation rate?"
I have created a repository with an implementation of this feature that works on iPhone/iPad in all orientations and highly customizable.
As mentioned in other answers, it's the inputAccessoryView that you're looking for.
I would like to add an alternative way here, by using this cocoapods:
pod 'UITextField-Navigation'
All UITextFields will have two additional properties: nextTextField and previousTextField. You can then simply connect the nextTextField in the Interface Builder and the Previous, Next and Done buttons are added automatically for you, all functional, no more code is needed, no subclassing.
You can also customize the UI, add more buttons, etc as you want to.

Which event get called when we hit UISearchBar

In my application, I need to do some activity i.e pushing otherview controller,when I click a UISearchbar which is added on view.
what is best approach to achive this.
As one of thing is when we click UISearchbar "searchBarTextDidBeginEditing" get fired,but with my scenario when I push view controller in "searchBarTextDidBeginEditing" and come back searchBarTextDidBeginEditing get called again, so seems it is not ideal place to push view controller.
This is maincontroller
// Search bar
iSearchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, 40)];
iSearchBar.delegate = self;
iSearchBar.showsCancelButton = NO;
iSearchBar.autocorrectionType = UITextAutocorrectionTypeNo;
iSearchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[self addSubview:iSearchBar];
when I click UISearchBar then it calls
- (void)searchBarTextDidBeginEditing:(UISearchBar*)searchBar
{
[self ShowMySearch];
}
In ShowMySearch , I am pushing some other controller lets say searchcontroller and when pop this searchcontroller and come back to maincontroller
"searchBarTextDidBeginEditing" get call again and searchcontroller is pushed again and causing issue. this behavior is seen only on 3.1.1
Thanks,
Sagar
I think calling [self ShowMySearch] in "searchBarTextDidBeginEditing" is a bit too late.
I suppose that "searchBarTextDidBeginEditing" is called on response to the search bar becoming first responder. Since it is the first responder when the search controller is pushed, it probably become first responder again when your search controller is poped out...thus calling "searchBarTextDidBeginEditing" once again.
To achieve this, I'd use :
(BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
This method is called after the search bar is tapped but before it becomes the first responder. And if you return NO, it will never become the first responder :
- (BOOL)searchBarShouldBeginEditing:(UISearchBar*)searchBar {
[self ShowMySearch];
return NO;
}
Let me know if this works !
For Swift 5.
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
handleShowSearchVC()
return false
}
#objc func handleShowSearchVC() {
let modalUserSearchController = UserSearchController(collectionViewLayout: UICollectionViewFlowLayout())
modalUserSearchController.modalPresentationStyle = .overCurrentContext
//Mini app panel.
//vc.view.frame = CGRectMake(0, vc.view.frame.size.height - 120, vc.view.frame.size.width, 120)
//Present #1
// present(modalUserSearchController, animated: true, completion: nil)
//Presentation #2
navigationController?.pushViewController(modalUserSearchController, animated: true)
}

How to programmatically replace UIToolBar items built in IB

I have a toolbar with various image buttons, created in Interface Builder.
I'd like to be able to programmatically replace one of the buttons with an activity indicator when pressed, and then put back the original button but change its color from white to yellow when the activity completes.
Is this possible with an IB built toolbar or must I look at building the whole toolbar programmatically and custom views?
Here is an example of what I did in a similar situation. I wanted to build the toolbar using Interface Builder but toggle one of the BarButtonItems based on whether or not it was "checked". In this example, there are a few key things to note. The following 2 member variables are defined for the class in the header file:
NSMutableArray *toolbarItems;
IBOutlet UIToolbar *toolbar;
NSUInteger checkUncheckIndex;
When I want to update the checked status, I call this function... Please note that there is a selector defined called checkUncheckClicked that is called when the particular button in the UIToolbar is clicked. And the UIToolbar is set up as an IBOutlet to toolbar. Alternately, you could hook up the UIBarButtonItem as an outlet itself and use that as your logic to identify the index of the button, or for that matter, you could hard-code the index of the button if things won't change over time. Finally, there is a checked.png and unchecked.png to alternate between that is included in the project.
- (void)updateBarButtonItemChecked:(BOOL)checked {
if (toolbarItems == nil) {
toolbarItems = [[NSMutableArray arrayWithArray:toolbar.items] retain];
checkUncheckIndex = -1;
for (NSUInteger i = 0; i < [toolbarItems count]; i++) {
UIBarButtonItem *barButtonItem = [toolbarItems objectAtIndex:i];
if (barButtonItem.action == #selector(checkUncheckClicked)) {
favoriteIndex = i;
break;
}
}
}
if (checkUncheckIndex != -1) {
UIBarButtonItem *barButtonItem = [[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:checked ? #"checked.png" : #"unchecked.png"]
style:UIBarButtonItemStylePlain target:self action:#selector(checkUncheckClicked)] autorelease];
[toolbarItems replaceObjectAtIndex:checkUncheckIndex withObject:barButtonItem];
toolbar.items = toolbarItems;
}
}
And, of course toolbarItems and toolbar should be released in your dealloc for the class.
Hope this helps!
Here is the approach I used
It seemed to be much simpler to manage the toolbar entirely programatically so ....
In your view controller declare 1 or more sets of UIBarButtonItem items as property items also declare and hookup the toolbar as a UIToolbar property. Also declare 1 or more arrays to hold the items.
In the implementation
In viewDidLoad alloc and set your UIBarButtonItems for example
playButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemPlay
target:self
action:#selector(handlePlayClick)];
Flexible buttons (for alignment etc) are declared like this
flexButton1 =[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
target:nil action:nil];
There are several initMethods to handle the different types of buttons toolbars support. All follow a syntax similar to the above. Worth noting is the target and action settings. Target: would normally be self, action is the name of the function that button should trigger.
After alloc'ng your UIBarButtons add them to an array using initWithObjects.
Then to assign the buttons to the toolbar you would call
[toolbar setItems:<array name>];
Dont forget to dealloc your UIBarButtons and arrays at the end of your code.
Hope this helps. If you need more code let me know.
Rich D.
Swift
Much has changed since these answers have been posted. Here is a Swift 2.0 solution.
It matters not how the original UIBarButtonItem you are replacing has been created programmatically. All you need is the UIToolbar outlet. To replace, say, the 2nd item from the left, do this:
var toolbarItems = self.toolbar.items
let newItem = UIBarButtonItem(barButtonSystemItem: .Play, target: self, action: "play")
toolbarItems![1] = newItem
self.toolbar.setItems(toolbarItems, animated: true)
Swift has a much easier way. In my case, I am switching the play button with the pause button every touch.
#IBAction func playandPause(sender: UIBarButtonItem) { // Here we are creating an outlet. Hook this up to the bar button item.
for (index, button) in toolbarItems!.enumerate() { // Enumerating through all the buttons
if button === sender { // === operator is used to check if the two objects are the exact same instance in memory.
var barButtonItem: UIBarButtonItem!
if mediaplayer.playing {
mediaplayer.pause()
barButtonItem = UIBarButtonItem.init(barButtonSystemItem: .Play, target: self, action: #selector(playandPause(_:)))
}else {
mediaplayer.play()
barButtonItem = UIBarButtonItem.init(barButtonSystemItem: .Pause, target: self, action: #selector(playandPause(_:)))
}
toolbarItems![index] = barButtonItem // Replace the old item with the new item.
break // Break once we have found the button as it is unnecessary to complete the rest of the loop
}
}
}
I think it should be possible. You might either try creating an IBOutlet for that specific button in your ViewController class, and connect the button from IB to that outlet, or you can use the items property of that UIToolbar instance (you do have a reference to that, don't you?) and find the appropriate item in there, create a new NSArray with modified items, and set it back on that toolbar.items property.
HTH
A note on this - the toolbar will strip out any color in your icons, so you still won't be able to make it yellow. You'll need to change the image shape to indicate "on" instead.
Alternatively you'll need to load your BarButtonItems with UIButtons (use the initWithCustomView) and set the image of the button appropriately.
HTH
Try:
- (void)setTitle:(NSString *)title forItem:(int)item ofToolbar:(UIToolbar *)tb {
NSMutableArray *newItems = [tb.items mutableCopy];
UIBarButtonItem *old = [newItems objectAtIndex:1],
*titled = [[UIBarButtonItem alloc] initWithTitle:title style:old.style target:old.target action:old.action];
[newItems replaceObjectAtIndex:1 withObject:titled];
tb.items = newItems;
[titled release];
}
For the entire toolbar that you created in IB (that is to say, not the individual toolbar items), create an IBOutlet:
#IBOutlet weak var toolbarThatYouMade: UIToolbar!
This is an array of individual toolbar items, so you would access the leftmost member (for example) with a [0] index:
toolbarThatYouMade.items![0].image = UIImage(named: "New Image")
This code assumes that you have an image named "New Image" in your assets.
You can then trigger an image change for a toolbar item without having to access that specific item itself; for example, if you were using this for something like a media player, you could toggle pause/play images from:
a) the Pause/Play button itself,
b) the Stop button,
c) when you are notified of a change of player state,
or
d) something else entirely. (Be brave! Be bold! Be something else that begins with 'b'!)