I used to use the following code to add a UIToolbar just above the UIKeyboard and being attached to it. I just switched to the iPhone OS 4 and I realized that it's not working anymore.
for (UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows]) {
for (UIView *keyboard in [keyboardWindow subviews]) {
//print all uiview descriptions
if([[keyboard description] hasPrefix:#"<UIKeyboard"] == YES) {
.. Some code to attach the UIToolbar
}
}
}
I realized that the code does not get into the if statement. I tried printing out all UIView descriptions just above the if and I could not see anything related to UIKeyboard. The code was working fine in OS 3.0 and 3.1. So does anyone have any idea about it?
You should try to use this below code:
- (BOOL) findKeyboard:(UIView *) superView;
{
UIView *currentView;
if ([superView.subviews count] > 0) {
for(int i = 0; i < [superView.subviews count]; i++)
{
currentView = [superView.subviews objectAtIndex:i];
NSLog(#"%#",[currentView description]);
if([[currentView description] hasPrefix:#"<UIKeyboard"] == YES)
{
NSLog(#"Find it");
//add toolbar here
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, -40, 100, 40)];
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Test button" style:UIBarButtonItemStyleBordered target:self action:#selector(buttonClicked:)];
NSArray *items = [[NSArray alloc] initWithObjects:barButtonItem, nil];
[toolbar setItems:items];
[items release];
[currentView addSubview:toolbar];
return YES;
}
if ([self findKeyboard:currentView]) return YES;
}
}
return NO;
}
-(void) checkKeyBoard {
UIWindow* tempWindow;
for(int c = 0; c < [[[UIApplication sharedApplication] windows] count]; c ++)
{
tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:c];
if ([self findKeyboard:tempWindow])
NSLog(#"Finally, I found it");
}
}
- (void)keyboardWillShow:(NSNotification *)note {
[self performSelector:(#selector(checkKeyBoard)) withObject:nil afterDelay:0];
}
And you also need to add this code to function didFinishLaunchingWithOptions in AppDelegate:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
Since you are relying on undocumented behavior, it should be no surprise that it does not work in 4.0 anymore. Use your views' inputAccessoryView property instead, which is the documented way to do this in OS 3.2+.
Related
I have tried the following code from another application but it doesn't find anything. Why? How to get access to the UIWebView toolbar?
- (UIToolbar *)findVirginWebKeyboardToolbar:(UIView *)parent
{
if ([parent isKindOfClass:[UIToolbar class]]) {
UIToolbar *tb = (UIToolbar *)parent;
if ([tb.items count] == 1 && [((UIBarButtonItem *)[tb.items objectAtIndex:0]).customView isKindOfClass:[UISegmentedControl class]]) {
return tb;
}
}
for (UIView *view in parent.subviews) {
UIToolbar *tb = [self findVirginWebKeyboardToolbar:view];
if (tb) return tb;
}
return nil;
}
- (void)removeKeyboardBar {
UIView *keyboardWindow = nil;
for (UIWindow *testWindow in [[UIApplication sharedApplication] windows]) {
keyboardWindow = testWindow;
UIToolbar *toolbar = [self findVirginWebKeyboardToolbar:keyboardWindow/*subviewWhichIsPossibleFormView*/];
if (toolbar) {
itemsArray = [NSArray arrayWithObjects:button1, button2, button3, nil];
[toolbar setItems:itemsArray];
}
}
}
With the following code you should be able to remove the toolbar that is above the keyboard.
-(void)viewWillAppear:(BOOL)animated{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
}
- (void)keyboardWillShow:(NSNotification *)note {
[self performSelector:#selector(removeBar) withObject:nil afterDelay:0];
}
- (void)removeBar {
// Locate non-UIWindow.
UIWindow *keyboardWindow = nil;
for (UIWindow *testWindow in [[UIApplication sharedApplication] windows]) {
if (![[testWindow class] isEqual:[UIWindow class]]) {
keyboardWindow = testWindow;
break;
}
}
// Locate UIWebFormView.
for (UIView *formView in [keyboardWindow subviews]) {
// iOS 5 sticks the UIWebFormView inside a UIPeripheralHostView.
if ([[formView description] rangeOfString:#"UIPeripheralHostView"].location != NSNotFound) {
for (UIView *subView in [formView subviews]) {
if ([[subView description] rangeOfString:#"UIWebFormAccessory"].location != NSNotFound) {
// remove the input accessory view
[subView removeFromSuperview];
}
else if([[subView description] rangeOfString:#"UIImageView"].location != NSNotFound){
// remove the line above the input accessory view (changing the frame)
[subView setFrame:CGRectZero];
}
}
}
}
}
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'm trying to add a "done" button to the UIKeyboadnumpad, but with no success.
What's wrong in my code?
the keyboard don't have the done button
#implementation DemoViewController
- (void)loadView {
self.view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
textField = [[UITextField alloc] initWithFrame:CGRectMake(10, 200, 300, 26)];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.keyboardType = UIKeyboardTypeNumberPad;
textField.returnKeyType = UIReturnKeyDone;
textField.textAlignment = UITextAlignmentLeft;
textField.text = #"12345";
[self.view addSubview:textField];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
}
- (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:0];
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 ([[[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)doneButton:(id)sender {
NSLog(#"Input: %#", textField.text);
[textField resignFirstResponder];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[textField release];
[super dealloc];
}
#end
Another solution. Perfect if there are other non-number pad text fields on the screen.
- (void)viewDidLoad
{
[super viewDidLoad];
UIToolbar* numberToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
numberToolbar.barStyle = UIBarStyleBlackTranslucent;
numberToolbar.items = [NSArray arrayWithObjects:
[[UIBarButtonItem alloc]initWithTitle:#"Cancel" style:UIBarButtonItemStyleBordered target:self action:#selector(cancelNumberPad)],
[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
[[UIBarButtonItem alloc]initWithTitle:#"Apply" style:UIBarButtonItemStyleDone target:self action:#selector(doneWithNumberPad)],
nil];
[numberToolbar sizeToFit];
numberTextField.inputAccessoryView = numberToolbar;
}
-(void)cancelNumberPad{
[numberTextField resignFirstResponder];
numberTextField.text = #"";
}
-(void)doneWithNumberPad{
NSString *numberFromTheKeyboard = numberTextField.text;
[numberTextField resignFirstResponder];
}
I needed the phone pad (with the +*#) and not the number pad, do I didn't even had the empty button in the corner.
Write your add button's code in
- (void)keyboardDidShow:(NSNotification *)note
instead of
- (void)keyboardWillShow:(NSNotification *)note
For this implement UIKeyboardDidShowNotification notification like :
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification object:nil];
I think UIView* keyboard; is not getting the keyboard's view as keyboard is not displayed yet, it will display !!!
Some of the tutorials are incomplete or are much older. This tutorial works from IOS 4.3 onwards and I checked it. Save the two image graphics, and paste in the code. There is very little to change. Here is the link.
ps. I am not affiliated in any way with this article, but found it to be complete.
http://www.neoos.ch/blog/37-uikeyboardtypenumberpad-and-the-missing-return-key
To make it short: take a screenshot, cut out the whole backspace key, flip it horizotally, clear its backspace symbol in Photoshop and overlay it with the text that we want on our return key. We’ve chosen to label it DONE.
Now we have the image for our custom button’s UIControlStateNormal.
Repeat the whole procedure (with a touched backspace key when taking the screenshot) to get a second image for our button’s UIControlStateHighlighted.
Here’s the result: <missing image>
Now back to coding:
First we need to know when the number pad is going to slide up on the screen so that we can plug our custom button before that happens.
Luckily there’s a notification for exactly that purpose and registering for it is as easy as:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
Don't forget to remove the observer from the notification center in the appropriate place once you're done with the whole thing:
[[NSNotificationCenter defaultCenter] removeObserver:self];
Now we’re getting to the heart of it. All we have to do in the keyboardWillShow method is to locate the keyboard view and add our button to it.
The keyboard view is part of a second UIWindow of our application as others have already figured out (see this thread).
So we take a reference to that window (it will be the second window in most cases, so objectAtIndex:1 in the code below is fine), traverse its view hierarchy until we find the keyboard and add the button to its lower left:
- (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 view found; add the custom button to it
if([[keyboard description] hasPrefix:#"UIKeyboard"] == YES)
[keyboard addSubview:doneButton];
}
}
Voilà, that’s it!
The empty space for our button starts at coordinate (0, 163) and has the dimensions (106, 53).
The doneButton method has to be written now of course, but that’s not hard any more. Just make sure that you call resignFirstResponder on the text field that is being edited to have the keyboard slide down.
We’re “DONE”.
how can i programmatically show/hide this opaque view from UISearchDisplayController?
Probably in searchDisplayControllerWillBeginSearch or searchDisplayControllerDidBeginSearch i need to set something... but what?
thanks.
Temporary solved using UIKeyboardWillAppearNotification.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow) name:UIKeyboardWillShowNotification object:nil];
OpaqueView is an UIControl with alpha = 0.8.
- (void) keyboardWillShow {
for( UIView *subview in self.view.subviews ) {
if( [subview isKindOfClass:[UIControl class]] ) {
UIControl *v = (UIControl*)subview;
if (v.alpha < 1) {
v.hidden = YES;
}
}
}
}
I used this ORRIBLE way to temporary fix problem.... any other idea will be appreciated!
thanks.
Code given by elpsk is current but will not work in iOS7 and above
Code working in both iOS6 and iOS7 is as below
- add below notification in viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow) name:UIKeyboardWillShowNotification object:nil];
Write below function
- (void) keyboardWillShow {
for( UIView *subview in self.view.subviews ) {
if([subview isMemberOfClass:[UIControl class]] ||
([[[subview class] description] isEqualToString:#"UISearchDisplayControllerContainerView"])) {
UIControl *v = (UIControl*)subview;
if (v.alpha < 1) {
v.hidden = YES;
}
}
}
}
NOTE : Code just have one extra condition as in iOS7 UIControl class become UISearchDisplayControllerContainerView,
The other answers where not working for me. This one works for me on iOS7 and iOS8.
for( UIView *subview in self.view.subviews ) {
if([subview isMemberOfClass:[UIControl class]] ||
([[[subview class] description] isEqualToString:#"UISearchDisplayControllerContainerView"])) {
for(UIView *subView2 in subview.subviews)
{
for(UIView *subView3 in subView2.subviews)
{
if (subView3.alpha < 1) {
subView3.hidden = YES;
}
}
}
}
}
If you don't need support for iOS7 please don't use the searchDisplayController anymore because its deprecated. For iOS8 use the UISearchController and the dimsBackgroundDuringPresentation
Property
Ref: https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UISearchController/index.html#//apple_ref/occ/instp/UISearchController/dimsBackgroundDuringPresentation
Mmmm...quick answer. Not pretty but surely works
#pragma mark UISearchBarDelegate
// Displays a view to simulate the lose of focus
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
searchBar.showsCancelButton = NO;
searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
UIButton *view1 = [[UIButton alloc] init];
view1.frame = CGRectMake(0, 0, 320, MAX(480, self.tableView.contentSize.height));
view1.alpha = 0.6;
view1.tag = 2000;
view1.backgroundColor = [UIColor blackColor];
[view1 addTarget:self
action:#selector(removeView)
forControlEvents:UIControlEventTouchUpInside];
[self.tableView setScrollEnabled:NO];
[self.tableView addSubview:view1];
[view1 release];
}
/**
* Pop the view and the keyboard
*/
- (void)removeView {
UIView *v = [self.tableView viewWithTag:2000];
v.hidden = YES;
[v removeFromSuperview];
[self.tableView setScrollEnabled:YES];
[self.searchBar resignFirstResponder];
}
That view is showed when you're writing, so I guess you should use it at searchBarTextDidBeginEditing. If I'm wrong, use it when you start searching or whatever.
Hi I have a big problem with iPhone 4.0 OS with this code
if([[keyboard description] hasPrefix:#"<UIKeyboard"] == YES) {
}
in condition UIKeyboard it not working. I try "UILayoutContainerView"
but it not working too.
please.
You can try this code:
- (BOOL) findKeyboard:(UIView *) superView;
{
UIView *currentView;
if ([superView.subviews count] > 0) {
for(int i = 0; i < [superView.subviews count]; i++)
{
currentView = [superView.subviews objectAtIndex:i];
NSLog(#"%#",[currentView description]);
if([[currentView description] hasPrefix:#"<UIKeyboard"] == YES)
{
NSLog(#"Find it");
return YES;
}
if ([self findKeyboard:currentView]) return YES;
}
}
return NO;
}
-(void) checkKeyBoard {
UIWindow* tempWindow;
for(int c = 0; c < [[[UIApplication sharedApplication] windows] count]; c ++)
{
tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:c];
if ([self findKeyboard:tempWindow])
NSLog(#"Finally, I found it");
}
}
- (void)keyboardWillShow:(NSNotification *)note {
[self performSelector:(#selector(checkKeyBoard)) withObject:nil afterDelay:0];
}
And you also need to add this code to function didFinishLaunchingWithOptions in AppDelegate:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
#"<UIPeripheralHostView" will work instead of #"<UIKeyboard"
Dunno why.
Can you tell me then: How to determine the keyboard type in the UIKeyboard class?