iOS/Objective-C: Add badge to custom UIBarButtonItem - ios

This is now very common but I cannot find a way to add a badge to a custom, or non-system, UIBarButton Item.
The following will add a badge to a systemUIBarButtonItem. But it does not work for one created from an image, i.e. a custom one. I would like to avoid creating a dependency on a separate class and would really like to find something similar to this that works for a custom button. Thanks in advance for any suggestions.
This creates badge for systemButton such as a search button:
UIBarButtonItem *searchButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSearch target:self action:#selector(searchButtonPressed)];
int badgeint = 4;
NSString *badgestring = [NSString stringWithFormat:#"%d",badgeint];
self.navigationItem.rightBarButtonItems = #[searchButton];
self.navigationItem.rightBarButtonItem.badgeValue = badgestring;
The same code for a custom button--there is no system button for notification so I need to use a custom image--does not produce the badge.
UIBarButtonItem *notificationButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"notification-32.png"] style:UIBarButtonItemStyleBordered target:self action:#selector(notificationButtonPressed)];
int badgeint = 4;
NSString *badgestring = [NSString stringWithFormat:#"%d",badgeint];
self.navigationItem.rightBarButtonItems = #[notificationButton];
self.navigationItem.rightBarButtonItem.badgeValue = badgestring;
Note: the reason I have barbuttonitems is that sometimes I use more than one)
Thanks for any suggestions
EDIT:
I found out that I made a stupid error--I set the value two different times. I thought the second would override the first, but apparently it confused it. There is no difference between system and custom buttons. I did discover, however, that if you have multiple buttons, the badge will always appear at the right of the group. Using this method, you can't seem to put the badge on a bar button item second in from right for example.

Related

How to change the badge background color in UIBarbutton?

I am using uibarbutton in my view to show the notification badge number. I have used following code to display.
barButtonBadge.badgeValue = #"5";
How can I change the background color of this badge number?
Right now it is taking default color.
Through your good question i got the solution from above Lalit Kumar link.
Add following two libraries in your project
1. UIButton+Badge.h and UIButton+Badge.m
2. UIBarButtonItem+Badge.h and UIBarButtonItem+Badge.m
Also import
#import "UIButton+Badge.h"
#import "UIBarButtonItem+Badge.h" in required view controller.
in your required ViewController.m
UIImage *image2 = [UIImage imageNamed:#"someImage"];
UIBarButtonItem *navRightButton = [[UIBarButtonItem alloc] initWithImage:image2
style:UIBarButtonItemStylePlain
target:self
action:#selector(buttonPress:)];
self.navigationItem.leftBarButtonItem = navRightButton;
self.navigationItem.leftBarButtonItem.badgeValue = #"2";
self.navigationItem.leftBarButtonItem.badgeBGColor = [UIColor orangeColor]; //Whatever you want just change the color

Can't get the icon for UIBarButtonSystemItemTrash

In order to get the trash image displayed in a standard toolbar on iOS. I am using the following code:
UIBarButtonItem *tempTBButn=[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:nil action:nil];
UIImage *trashImg=tempTBButn.image;
But it does not work. The result I get in trashImg is just nil.
What should I do to obtain the result I want? That is to have the trash icon in trashImg.
The image property is only set when you create a UIBarButtonItem with one of the custom image init methods like:
UIBarButtonItem *customImageBarButtonItem = [[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:#"yourImage"] style:UIBarButtonItemStylePlain target:self action:#selector(barButtonItemPressed:)];
The image property defaults to nil when you use the initWithBarButtonSystemItem: method. Your best bet is to just use a trash icon of your own, or work with just having the standard icon on the nav.

Issue with custom number pad in iOS app

I have an app with a custom number pad. I need the custom number pad for some, but not all of the text fields on a preferences view. I have written this method to set up the number pad for certain text fields:
-(void)setNumberPadFor:(UITextField*)textField andNibName:(NSString *)nibNamed{
textField.inputView = [[[NSBundle mainBundle] loadNibNamed:nibNamed
owner:self
options:nil] lastObject];
UIBarButtonItem *btnDone = [[UIBarButtonItem alloc] initWithTitle:#"Done"
style:UIBarButtonItemStyleDone
target:textField
action:#selector(resignFirstResponder)];
UIToolbar *tips = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
tips.barStyle = UIBarStyleBlackOpaque;
[tips setBackgroundColor:[UIColor blueColor]];
[tips setTintColor:[UIColor whiteColor]];
UIBarButtonItem *spacer = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
target:nil
action:nil];
[tips sizeToFit];
tips.items = [NSArray arrayWithObjects:spacer, btnDone, nil];
textField.inputAccessoryView = tips;
}
I am calling the setup method as follows (in viewDidLoad for the ViewController):
[self setNumberPadFor:txtMinFeet andNibName:#"PosNegNumberPad"];
[self setNumberPadFor:txtMaxFeet andNibName:#"PosNegNumberPad"];
So, in my button click events, how do I access the text field that initiated the number pad?
-(IBAction)btnNum1:(id)sender{
[[UIDevice currentDevice] playInputClick];
// update text field
}
-(IBAction)btnNum2:(id)sender{
[[UIDevice currentDevice] playInputClick];
// update text field
}
Eventually I will have two custom number pads to cover the requirements, but for now there is just one (hence one nib currently passed as a parameter).
My button actions are set up and working, that is, I can set a break point inside them and verify the app is responding to the events.
What I am unclear about is how to identify which text field initiated the number pad so I can update it accordingly.
Obviously I'm leaving something out. Any suggestions? Thanks!
One way is to use an ivar and every time you get the delegate method textFieldDidBeginEditing: you set the ivar. Later, you query the ivar to get the current text field.
The other way to do is is to find the first responder. This means traversing the subviews of your primary view to find it. This is common enough that you can find code to do that here for sure. The other way is the easiest to do.

Stuck with UIActionSheetPicker , iOS

This is going to be a very targeted question , as its for people that have actually used the UIActionSheetPicker before.
I used it in my iphone applications and everything worked great , but now that i tried to implement it on my ipad i experienced some problems.
The main problem is that on ipad the picker appears as a "bubble" or "info window" if you prefer , which points at the spot where it was called , like a button a text field etc.
Below is an example of it :
You can see that the "info window" is pointing at the animals button.
In my application i have 4 different buttons. 2 are in the top side of the screen and 2 at the bottom.
Those who are at the bottom , call the picker very well and the picker appears on top of the buttons pointing down on them.
However , the ones on the top of the screen (almost like the one in the image) when they call the picker the picker appears much lower on the screen and doesnt point at them as it should ...
I mean i expected to appear just under the buttons pointing at them (like in the image), but they are almost in the center of the screen pointing nowhere..
Any ideas? Has someone experienced this before?
EDIT
In the beginning , i was calling the ActionSheetPicker inside the buttons action like this:
- (IBAction)selectTopic:(UIControl *)sender {
[ActionSheetStringPicker showPickerWithTitle:NSLocalizedString(#"CHOOSE_TOPIC", nil) rows:self.topics initialSelection:self.selectedIndex target:self successAction:#selector(topicWasSelected:element:) cancelAction:#selector(actionPickerCancelled:) origin:sender];
//when user picks a new topic we clean the titleField to make sure selected title of previous topic doesnt mix up with new topic
titleField.text = #"";
}
Now i am trying to call it like this:
- (IBAction)selectTopic:(UIControl *)sender {
ActionSheetStringPicker *thePicker = [[ActionSheetStringPicker alloc] initWithTitle:NSLocalizedString(#"CHOOSE_TOPIC", nil) rows:self.topics initialSelection:self.selectedIndex target:self successAction:#selector(topicWasSelected:element:) cancelAction:#selector(actionPickerCancelled:) origin:sender];
thePicker.presentFromRect = topicField.frame;
[thePicker showActionSheetPicker];
//when user picks a new topic we clean the titleField to make sure selected title of previous topic doesnt mix up with new topic
titleField.text = #"";
}
Where topicField is my TextField.
Sadly the result is the same. Even now that i am specifying where i want the arrow to point , the picker is called 300 pixels down.
The strange thing is though that even with another other button that is a bit lower than the previous the picker is again exactly 300 pixels down.
EDIT2
After noticing that the picker shows 300 pixels down , i decided to manually make it show 300pixels up , to point exactly on my button.
I used the following code :
- (IBAction)selectTopic:(UIControl *)sender {
//[ActionSheetStringPicker showPickerWithTitle:NSLocalizedString(#"CHOOSE_TOPIC", nil) rows:self.topics initialSelection:self.selectedIndex target:self successAction:#selector(topicWasSelected:element:) cancelAction:#selector(actionPickerCancelled:) origin:sender];
ActionSheetStringPicker *thePicker = [[ActionSheetStringPicker alloc] initWithTitle:NSLocalizedString(#"CHOOSE_TOPIC", nil) rows:self.topics initialSelection:self.selectedIndex target:self successAction:#selector(topicWasSelected:element:) cancelAction:#selector(actionPickerCancelled:) origin:sender];
CGRect pickerFrame = topicField.frame;
pickerFrame.size.height -= 300;
thePicker.presentFromRect = pickerFrame;
[thePicker showActionSheetPicker];
//when user picks a new topic we clean the titleField to make sure selected title of previous topic doesnt mix up with new topic
titleField.text = #"";
}
Amazingly the button once again appears in the same position 300pixels down. I start to believe that this one may not be the property to alter the position of the picker.
Any ideas ?
Setting the presentFromRect in your calling code won't make a difference since it will be reset based on the sender within the ActionSheetPicker code, instead you are going to need to modify the source code of the library.
The following (unmerged) commit on github should resolve the issue On iPad, set the popover to point properly at its container.
Basically within the AbstractActionSheetPicker.m file modify the - (void)presentPickerForView:(UIView *)aView method like the following
- (void)presentPickerForView:(UIView *)aView {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
self.presentFromRect = CGRectMake(0, 0, self.containerView.frame.size.width, self.containerView.frame.size.height);
[self configureAndPresentPopoverForView:aView];
}
else {
self.presentFromRect = aView.frame;
[self configureAndPresentActionSheetForView:aView];
}
}
After a brief look at the code, I would say that you want to make sure that the presentFromRect on the ActionPicker object is in the coordinates of the container that you are passing in on the init. For instance if I had one big view that contained a button:
This is untested:
UIView* someBigView = ... // get the big view
UIButton* someButton = ... // get the button that the big view contains
ActionSheetDatePicker* thePicker = [[ActionSheetDatePicker alloc] initWithTitle:#"Some Title"
datePickerMode:UIDatePickerModeDate
selectedDate:[NSDate date]
target:self
action:#selector(someMethod:)
origin:someBigView];
//the arrow should be pointing at the button
thePicker.presentFromRect = someButton.frame;
[thePicker showActionSheetPicker];
In my opinion, this library has a pretty big flaw in the fact that it takes an origin parameter that can be a button item or a container. It requires that you look at the source to understand it, instead of being (somewhat) obvious from the interface.

UIBarButtonItem not centered

I've added a single button to the center of a toolbar using:
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self
action:nil];
UIBarButtonItem *spacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
target:nil
action:nil];
self.toolbarItems = #[spacer, addButton, spacer];
But the added button is not quite centered:
What is going on here?
Don't add the same spacer twice in the array - the value may be different in each - make two spacers.
I'm starting to think it's some sort of an iOS-wide bug. That, or they got it wrong in many places. For example, paging dots on home page aren't centered. The Notification Center's top 3 buttons (Today, All, Missed) are also a few pixels off. Plenty more like that. So this may be corrected in the next update.
For now, I'd try to force it to center (say, in viewWillAppear). Pseudo-code below, no time to test :P:
self.toolbarItems[1].center = CGPointMake(self.bounds.size.width / 2.0f, self.bounds.size.height / 2.0f);

Resources