I am trying to add a custom done button on the UIKeyboard (the number pad specifically). I have followed all the examples to do this online but I can't get the button to appear above the keyboard. Below is my code (mainly patched together from online examples):
UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
doneButton.frame = CGRectMake(214, 427, 106, 53);
doneButton.adjustsImageWhenHighlighted = NO;
[doneButton setImage:[UIImage imageNamed:#"DoneUp.png"] forState:UIControlStateNormal];
[doneButton setImage:[UIImage imageNamed:#"DoneDown.png"] forState:UIControlStateHighlighted];
[doneButton addTarget:self action:#selector(doneButton:) forControlEvents:UIControlEventTouchUpInside];
UIWindow *tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
UIView *keyboard;
for(int i=0; i<[tempWindow.subviews count]; i++)
{
keyboard = [tempWindow.subviews objectAtIndex:i];
if([[keyboard description] hasPrefix:#"<UIKeyboardTypeNumberPad"] == YES)
[keyboard addSubview:doneButton];
}
Am I doing something wrong?
(This code is called after the keyboard is displayed).
EDIT:
I am showing the keypad in a modal view controller which is the child of a UINavigationController. In all the sample code I've tried the problem seems to be with this line:
if([[keyboard description] hasPrefix:#"<UIKeyboardTypeNumberPad"] == YES)
which is returning NO. I have tested this using the UIKeyboardDidShow notification so the keyboard is definitely visible when the code is called.
The way you are trying is hard-code hacking and violating HIG I think.
If you want to customize keyboard, you should create your own keyboard and set it to your UIResponder's inputView.
I figured out the solution. In iOS4.0 Apple changed the description of the keyboard so you now have to use UIPeripheralHostView (this is clearly not the best way to implement this solution if Apple can change that value at any time). My positioning of the button was also off as I was positioning the y coordinate against the whole view instead of just the keyboard. Here is the final code:
- (void)keyboardDidShow:(NSNotification *)note {
// create custom button
UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
doneButton.frame = CGRectMake(215, 163, 106, 53);
doneButton.adjustsImageWhenHighlighted = NO;
[doneButton setImage:[UIImage imageNamed:#"DoneUp.png"] forState:UIControlStateNormal];
[doneButton setImage:[UIImage imageNamed:#"DoneDown.png"] forState:UIControlStateHighlighted];
[doneButton addTarget:self action:#selector(doneButton:) forControlEvents:UIControlEventTouchUpInside];
UIWindow* tempWindow;
UIView* keyboard;
for(int c = 0; c < [[[UIApplication sharedApplication] windows] count]; c ++)
{
tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:c];
for(int i = 0; i < [tempWindow.subviews count]; i++)
{
keyboard = [tempWindow.subviews objectAtIndex:i];
if([[keyboard description] hasPrefix:#"<UIPeripheralHostView"] == YES)
{
[keyboard addSubview:doneButton];
}
}
}
}
Related
I have a layout where i have two text fields one is for alphabetic input and another one for numeric input. I have set different type of keyboards for these like as default for alphabetic text field and number for numeric field.
I have added a done button on number pad. Still I am getting this a issue with keyboards that is when I taped on numeric text filed first then it show done button keyboard while I taped alphabetic text filed first and then taped on numeric text field then it doesn't add done button on number pad.
How do I solve it?
I have use these code to add button on number pad.
-(void)viewWillAppear:(BOOL)animated
{
// Register for the events
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector (keyboardDidShow:) name: UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector (keyboardDidHide:) name: UIKeyboardDidHideNotification object:nil];
keyboardVisible = NO;
scroll_view.contentSize=CGSizeMake(320, 400);
}
- (void)keyboardDidShow:(NSNotification *)note {
UIWindow* tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
UIView* keyboard;
for (keyboard in tempWindow.subviews) {
if([[keyboard description] hasPrefix:#"<UIKeyboard"] == YES)
if (numberPadShowing) {
[self addButtonToKeyboard];
return;
break;
} else {
for (UIView *v in [keyboard subviews]){
if ([v tag]==123)
[v removeFromSuperview];
}
}
}
}
-
(void) keyboardDidHide: (NSNotification *)notif
{
// Is the keyboard already shown
if (!keyboardVisible) {
return;
}
// Keyboard is no longer visible
keyboardVisible = NO;
}
-(void)doneButton
{
UIScrollView *scrollView =[[UIScrollView alloc] init];
scrollView=scroll_view;
[scrollView setContentOffset:svos animated:YES];
[myActiveTextField resignFirstResponder];
}
- (void)addButtonToKeyboard {
// create custom button
UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
doneButton.frame = CGRectMake(0, 163, 106, 53);
doneButton.adjustsImageWhenHighlighted = NO;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 3.0) {
[doneButton setImage:[UIImage imageNamed:#"DoneUp3.png"] forState:UIControlStateNormal];
[doneButton setImage:[UIImage imageNamed:#"DoneDown3.png"] forState:UIControlStateHighlighted];
} else {
[doneButton setImage:[UIImage imageNamed:#"DoneUp.png"] forState:UIControlStateNormal];
[doneButton setImage:[UIImage imageNamed:#"DoneDown.png"] forState:UIControlStateHighlighted];
}
[doneButton addTarget:self action:#selector(doneButton) forControlEvents:UIControlEventTouchUpInside];
// locate keyboard view
UIWindow* tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
UIView* keyboard;
for(int i=0; i<[tempWindow.subviews count]; i++) {
keyboard = [tempWindow.subviews objectAtIndex:i];
// keyboard found, add the button
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 3.2) {
if([[keyboard description] hasPrefix:#"<UIPeripheralHost"] == YES)
[keyboard addSubview:doneButton];
} else {
if([[keyboard description] hasPrefix:#"<UIKeyboard"] == YES)
[keyboard addSubview:doneButton];
}
}
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
myActiveTextField=textField;
if (myActiveTextField==txt_hour_section || myActiveTextField==txt_minute_section || myActiveTextField==txt_transport_time){
numberPadShowing=TRUE;
UIScrollView *scrollView =[[UIScrollView alloc] init];
scrollView=scroll_view;
svos = scrollView.contentOffset;
CGPoint pt;
CGRect rc = [textField bounds];
rc = [textField convertRect:rc toView:scrollView];
pt = rc.origin;
pt.x = 0;
pt.y -= 60;
[scrollView setContentOffset:pt animated:YES];
}
else{
numberPadShowing=FALSE;
}
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
UIScrollView *scrollView =[[UIScrollView alloc] init];
scrollView=scroll_view;
[scrollView setContentOffset:svos animated:YES];
[textField resignFirstResponder];
return YES;
}
Thanks in advances...
I think your problem is becuase you are tapping in to the numeric field after tapping the alpha field, and the alpha keyboard is already in view. Therefore when you tap the number field (whilst alpha keyboard still in view) it doesn't fire the 'keyboardDidShow' event, as the keyboard is already showing from the previous field (albeit a alpha one).
Try putting your done button logic into a delegate method for the textfield 'textFieldDidBeginEditing' event for the number field.
If my first answer doesn't work in your implementation, then you might want to consider a restructure and go for setting the inputAccessoryView of your UITextField. Code along these lines should do the trick (you can put this in your viewDidLoad nib, and also note that you'll need to implement the doneTapped method yourself);
// Create a UIToolbar object and set its style to be black and transparent
numericInputAccessoryView_ = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
numericInputAccessoryView_.barStyle = UIBarStyleBlackTranslucent;
// The flexible space item will push the done button to the far right
UIBarButtonItem *space = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
// Make the done button, this is a system item so you don't need to set the title or anything. This will call a method called "doneTapped:(id)sender" when you tap it, you'll need to implement that yourself.
UIBarButtonItem *done = [[UIBarButtonItem alloc]WithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(doneTapped:)];
// Stick the flexible space and the done button in your toolbar
numericInputAccessoryView_.items = [NSArray arrayWithObjects:space,done, nil];
// This would return it, if you had this in a separate method.
return numericInputAccessoryView_;
I am using a text field to enter mobile nuber and I would like to add done button to hide the keyboard, following is my code
- (void)keyboardWillShow:(NSNotification *)note {
// create custom button
UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
doneButton.frame = CGRectMake(0, 163, 106, 53);
doneButton.adjustsImageWhenHighlighted = NO;
[doneButton setImage:[UIImage imageNamed:#"doneup.png"] forState:UIControlStateNormal];
[doneButton setImage:[UIImage imageNamed:#"donedown.png"] forState:UIControlStateHighlighted];
[doneButton addTarget:self action:#selector(doneButton:) forControlEvents:UIControlEventTouchUpInside];
// locate keyboard view
UIWindow* tempWindow = [[[UIApplication sharedApplication] windows]objectAtIndex:1];
UIView* keyboard;
for(int i=0; i<[tempWindow.subviews count]; i++) {
keyboard = [tempWindow.subviews objectAtIndex:i];
// keyboard found, add the button
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 3.2) {
if([[keyboard description] hasPrefix:#"<UIPeripheralHost"] == YES)
[keyboard addSubview:doneButton];
} else {
if([[keyboard description] hasPrefix:#"<UIKeyboard"] == YES)
[keyboard addSubview:doneButton];
}
}
}
but I am unable to add the done button ,after cross check with break points , I observe that control is not entering into the if([[keyboard description] hasPrefix:#"UIKeyboard"] == YES) conditon.
I am using IOS5.
I did add a custom done-button in one of my projects too. The tutorial I used mentioned that piece of code:
if([[[UIDevice currentDevice] systemVersion] floatValue] >= 3.2)
{
if([[tmpKeyboard description] hasPrefix:#"<UIPeripheralHost"] == TRUE)
[tmpKeyboard addSubview:doneButton];
}
else
{
if([[tmpKeyboard description] hasPrefix:#"<UIKeyboard"] == TRUE)
[tmpKeyboard addSubview:doneButton];
}
Prior to iOS version 3.2 your approach with UIKeyboard is fine, but later you have to change it to UIPeripheralHost.
In iOS 3 this workaround involved creating a customer UIButton and adding this as a subview to the Apple keyboard. When iOS 4 was released the view that the subview was added to changed. So to get this working in iOS3 & 4 I had the following.
-(void) addDoneButtonToNumericKeyboard {
if(doneButtonIsAdded) {
return;
}
if(doneButtonForNumericKeyboard == nil) {
doneButtonForNumericKeyboard= [[UIButton buttonWithType:UIButtonTypeCustom] retain];
doneButtonForNumericKeyboard.frame = CGRectMake(0, 163, 106, 53);
doneButtonForNumericKeyboard.adjustsImageWhenHighlighted = NO;
if ([[[UIDevice currentDevice] systemVersion] hasPrefix:#"3"]) {
[doneButtonForNumericKeyboard setImage:[UIImage imageNamed:#"DoneUp3.png"] forState:UIControlStateNormal];
[doneButtonForNumericKeyboard setImage:[UIImage imageNamed:#"DoneDown3.png"] forState:UIControlStateHighlighted];
} else {
[doneButtonForNumericKeyboard setImage:[UIImage imageNamed:#"DoneUp.png"] forState:UIControlStateNormal];
[doneButtonForNumericKeyboard setImage:[UIImage imageNamed:#"DoneDown.png"] forState:UIControlStateHighlighted];
}
[doneButtonForNumericKeyboard addTarget:self action:#selector(doneButton:) forControlEvents:UIControlEventTouchUpInside];
}
// locate keyboard view
NSArray *winArray = [[UIApplication sharedApplication] windows];
if(winArray == nil || [winArray count] < 2) {
NSLog(#"No winArray found!");
return;
}
UIWindow* tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
UIView* keyboard;
for(int i=0; i<[tempWindow.subviews count]; i++) {
keyboard = [tempWindow.subviews objectAtIndex:i];
// keyboard view found; add the custom button to it
NSLog(#"Keyboard description : %#", [keyboard description]);
if([[keyboard description] hasPrefix:#"<UIKeyboard"] == YES || [[keyboard description] hasPrefix:#"<UIPeripheralHost"] == YES) {
NSLog(#"Attaching done button");
[keyboard addSubview:doneButtonForNumericKeyboard];
doneButtonIsAdded = YES;
}
}
}
Anyone have any ideas how to get this working for iOS 5?
Neither of the methods above work for 5. There is an attempt to add the subview that seems to be successful but nothing is displayed. The area is just blank on screen and does not respond to a touch.
I noticed this as well and the only fix I was able to come up so far was to change it from: keyboardWillShow: to keyboardDidShow:. The difference between "will" and "did" is obviously another discussion but it seems that fixed it for my needs.
I hope this helps.
Some more background on what I found is that the [[UIApplication sharedApplication] windows] the first object does appear to be there but the second object, at index 1, is gone. I wonder what caused this.
Thanks.
how do i make these buttons so that only one can be used at a time? Im not getting any errors right now when i run btw. Im just looking for a solution to my challenge. Thanks for any help
they are generated in a for loop like this:
for (int l=0; l<list.length; l++) {
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[aButton setTag:l];
CGRect buttonRect = CGRectMake(11+charact*20, -40 + line*50, 18, 21);
aButton.frame = buttonRect;
[aButton addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[aButton setTitle:#" " forState:UIControlStateNormal];
[gameScroll addSubview:aButton];
}
And then the action for when a button is clicked is:
- (void) buttonClicked:(UIButton *)sender {
int tag = sender.tag;
if (sender.selected == TRUE) {
[sender setSelected:FALSE];
[sender setBackgroundColor:[UIColor clearColor]];
}
else if (sender.selected == FALSE) {
[sender setSelected:TRUE];
[sender setBackgroundColor:[UIColor redColor]];
}
}
right now everything works but i want it to know if theres already a button selected and deselect that other button, or else to automatically deselect any time the user clicks outside of the range of that button
thanks in advance
I would suggest to put all ur buttons to Array in your button initialisation
NSMutableArray* buttons = [NSMutableArray arrayWithCapacity: list.length];
for (int l=0; l<list.length; l++) {
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[aButton setTag:l];
CGRect buttonRect = CGRectMake(11+charact*20, -40 + line*50, 18, 21);
aButton.frame = buttonRect;
[aButton addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[aButton setTitle:#" " forState:UIControlStateNormal];
[gameScroll addSubview:aButton];
[buttons addObject: aButton];
}
and every time buttonClicked triggered, then do your logic:
for (UIButton* button in buttons)
{
if (button != sender)
{
[button setSelected: FALSE];
[button setBackgroundColor:[UIColor redColor]];
}
}
int tag = sender.tag;
if (sender.selected == TRUE) {
[sender setSelected:FALSE];
[sender setBackgroundColor:[UIColor clearColor]];
}
else if (sender.selected == FALSE) {
[sender setSelected:TRUE];
[sender setBackgroundColor:[UIColor redColor]];
}
hope helps :)
You can store currently selected button in a separate variable and deselect it in buttonClicked: method:
- (void) buttonClicked:(UIButton *)sender {
int tag = sender.tag;
currentButton.selected = NO;
if (currentButton != sender){
currentButton = sender;
currentButton.selected = YES;
}
else{
currentButton = nil;
}
}
Also you can specify background colour for each state in button itself so you actually don't need to change it each time manually
If you also want to deselect your button when user just touches the screen you can implement touchesEnded:withEvent: in your view controller and reset currentButton in it (that method will get called if no other control intercept the touch event - so it may not be sufficient in all cases)
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event{
currentButton.selected = NO;
currentButton = nil;
}
I've set up a Button and add it to a view. I want to add a "done" button to the UIKeyboardTypeNumberPad. Here's my code.
UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
doneButton.frame = CGRectMake(0, 163, 106, 53);
doneButton.adjustsImageWhenHighlighted = NO;
[doneButton setImage:[UIImage imageNamed:#"DoneUp.png"] forState:UIControlStateNormal];
[doneButton setImage:[UIImage imageNamed:#"DoneDown.png"] forState:UIControlStateHighlighted];
[doneButton addTarget:self action:#selector(doneButton:) forControlEvents:UIControlEventTouchUpInside];
// locate keyboard view
UIWindow* tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
UIView* keyboard;
for(int i=0; i<[tempWindow.subviews count]; i++) {
keyboard = [tempWindow.subviews objectAtIndex:i];
// keyboard view found; add the custom button to it
if([[keyboard description] hasPrefix:#"<UIKeyboard"] == YES)
[keyboard addSubview:doneButton];
}
Everything works great until I want to remove the button if I've got a Kayboard of type NumbersAndPunctuation for example.
If I click the button I use [(UIButton)*sender removeFromSuperview];
to prevent memory leaks.
But how do I remove the button from within an other function?
Thanks a lot!
Some other guys did ask that question somewhere else but didn't get a answer. I'am sure you can help :)
// Where self is a UIView subclass
NSLog(#"subviews: %#",self.subviews);
for(id view in self.subviews ){
if ([view isKindOfClass:[UIButton class]]) {
NSLog(#"Removing a button!");
[view removeFromSuperview];
}
}
You should store a reference to the button, instead of using a local variable. For example:
Header file:
#interface myObject : NSObject {
UIButton *doneButton;
...
Implementation file:
doneButton = [UIButton buttonWithType: UIButtonTypeCustom
...
To remove it (assuming you're in the same object:
[doneButton removeFromSuperview];
However, Apple may not take kindly to you adding buttons to their keyboard.
you can declare your button in your .h file, so you will be able to get access from all class methods