 |
 |
|
 |
11-08-2008, 10:53 AM
|
#1 (permalink)
|
|
New Member
Join Date: Nov 2008
Posts: 1
|
Add toolbar on top of keyboard
Some apps – like Twinkle e.g. – add a custom toolbar on top of the existing keyboard mostly to add "send" or "done" buttons. These toolbars animate in from the bottom along with the keyboard.
Is anybody aware of how this can be done?
|
|
|
11-08-2008, 11:24 AM
|
#2 (permalink)
|
|
New Member
Join Date: Oct 2008
Location: Denver, CO
Posts: 2,121
|
I added a label to the top of the keyboard in my app. I can explain how to add a subview to the keyboard.
First you need to register to receive keyboard notifications. I have the following in my app delegate:
Code:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
Here is a snippet from my 'keyboardWillShow'. This allows you to get info about the size and location of the keyboard.
Code:
- (void)keyboardWillShow:(NSNotification *)note {
NSDictionary *info = [note userInfo];
NSValue *beginPoint = [info objectForKey:UIKeyboardCenterBeginUserInfoKey];
NSValue *endPoint = [info objectForKey:UIKeyboardCenterEndUserInfoKey];
NSValue *keyBounds = [info objectForKey:UIKeyboardBoundsUserInfoKey];
CGPoint pntBegin;
CGPoint pntEnd;
CGRect bndKey;
[beginPoint getValue:&pntBegin];
[endPoint getValue:&pntEnd];
[keyBounds getValue:&bndKey];
}
The next trick is actually finding the keyboard view. The keyboard view is actually in a second UIWindow separate from your app's main window. So you need to write code to walk all of the windows in the app. Then for each window you need to find the one that has a subview containing the keyboard. I do this by finding the subview whose description contains the string 'UIKeyboard'. I do this to avoid compiler warnings because the real class for the keyboard view isn't exposed via the SDK. But all you need is a UIView reference anyway.
Once you get the keyboard view, along with the coordinates you got earlier, you can now add a subview to the keyboard view.
I'm not going to give all the code because I worked very hard to figure this out on my own and it gives my app a little edge. Hopefully the info I gave will get you far enough to figure the details out.
Enjoy.
|
|
|
12-15-2008, 10:33 PM
|
#3 (permalink)
|
|
New Member
Join Date: Dec 2008
Posts: 2
|
I stumbled upon this post and found it very helpful.
@RickMaddy, I'm trying to do something similar to what you've described, but instead of adding a UILabel, I'm trying to add a UIToolbar and a UIBarButtonItem that the user can click. I've been able to add the toolbar and the button, but my problem is, the toolbar button is only able to be clicked if it's on TOP of the keyboard. If I add the toolbar as a subview ABOVE the keyboard, then the button cannot be clicked. Here's the relevant code snippet from the keyboardWillShow: method. (Thanks to both RickMaddy and keyboardcowboy for the posts. Much of the code below is taken from their posts.)
Code:
- (void)keyboardWillShow:(NSNotification *)note
{
NSDictionary *info = [note userInfo];
NSValue *keyBounds = [info objectForKey:UIKeyboardBoundsUserInfoKey];
CGRect bndKey;
[keyBounds getValue:&bndKey];
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, -40, bndKey.size.width, 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];
UIWindow* tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
UIView* keyboard;
for(int i = 0; i < [tempWindow.subviews count]; i++)
{
//Get a reference of the current view
keyboard = [tempWindow.subviews objectAtIndex:i];
//Check to see if the description of the view we have referenced is "UIKeyboard" if so then we found
//the keyboard view that we were looking for
if([[keyboard description] hasPrefix:@"<UIKeyboard"] == YES)
{
[keyboard addSubview:toolbar];
}
}
}
- (void)buttonClicked:(NSNotification *)note
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"You clicked the keyboard button!" message:@"Hey! You clicked the button on top of the keyboard." delegate:self cancelButtonTitle:@"Yep" otherButtonTitles:nil];
[alert show];
[alert release];
}
With the above code, the toolbar is added just above the keyboard, and there's a button labeled "Test button" on the toolbar. However, it doesn't accept user interaction. BUT if you change the code where the toolbar is created to the following (keep everything else the same):
Code:
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, bndKey.size.width, 40)];
Now, the toolbar is added ON TOP OF (overlaying) the keyboard (not where we want it) but the button works in this case.
Any suggestions for how to get the button to work when it's just above the keyboard?
|
|
|
12-15-2008, 10:43 PM
|
#4 (permalink)
|
|
New Member
Join Date: Oct 2008
Location: Denver, CO
Posts: 2,121
|
I'm not positive but I think the problem lies with the fact that the button is actually located with a bounding box outside of it's parent's (grandparent's actually) view. I saw this once before. Buttons don't get touch events if their bounding box is outside the frame of their parent view.
I've never tried this, and it may make the code even more fragile to future changes by Apple, but you might be able to resize and reposition the keyboard view so it extends high enough so you can place the toolbar within its frame. Yuck.
|
|
|
12-15-2008, 10:46 PM
|
#5 (permalink)
|
|
New Member
Join Date: Oct 2008
Location: Denver, CO
Posts: 2,121
|
Ooh, I just had an idea that might work. Add the toolbar with the negative offset so it animates and appears in the correct position. Then after you get the 'keyboard did appear' event, change the toolbar's superview to the window or some other, bigger view. When you get the event 'keyboard will hide', put it back so the superview is the keyboard again so it properly animates out of view.
Just guessing but this may work.
|
|
|
12-16-2008, 12:39 AM
|
#6 (permalink)
|
|
New Member
Join Date: Dec 2008
Posts: 2
|
Great suggestion! You were right on. On the keyboardDidShow: method, I removed the toolbar from the keyboard's view and added it as a subview to the UIWindow and now it works great! Your help is much appreciated.
|
|
|
12-16-2008, 09:01 AM
|
#7 (permalink)
|
|
Registered Member
Join Date: Nov 2008
Posts: 59
|
thank,for discussing i am searching for some UIKeyboard related tutorial
you solve my problem also.
thank's again
|
|
|
01-18-2009, 03:32 PM
|
#8 (permalink)
|
|
New Member
Join Date: Jan 2009
Posts: 4
|
Quote:
Originally Posted by RickMaddy
...Then after you get the 'keyboard did appear' event, change the toolbar's superview to the window or some other, bigger view...
|
How do you change the superview? I can't get it to work... :-/
|
|
|
01-18-2009, 07:35 PM
|
#9 (permalink)
|
|
New Member
Join Date: Oct 2008
Location: Denver, CO
Posts: 2,121
|
[someView removeFromSuperview];
[newParentView addSubview:someView];
|
|
|
01-19-2009, 02:49 AM
|
#10 (permalink)
|
|
New Member
Join Date: Jan 2009
Posts: 4
|
Thats what I tried. Just tried to add it to the wrong superview. :P
Thanks for the quick reply anyway.
|
|
|
03-21-2009, 04:21 PM
|
#11 (permalink)
|
|
New Member
Join Date: Mar 2009
Posts: 1
|
Thank you for discussing. To which UIWindow did you add the toolbar as a subView? ... After I do removeFromSuperview the toolbar disappears.
Thanks.
|
|
|
04-20-2009, 11:08 AM
|
#12 (permalink)
|
|
New Member
Join Date: Jan 2009
Posts: 2
|
My Solution
This thread got me started, so here's my solution. As with the intial approach on this thread I retrieve the keyboard from the notification. I then take it one step further. After adding my UIToolbar to the keyboard I rebound the keyboard view. So the toolbar and they keyboard will both collect touch events within the Keyboard class frame. Handles rotation as well.
Code:
- (void)keyboardWillShow:(NSNotification *)notification
{
for (UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows]) {
// Now iterating over each subview of the available windows
for (UIView *keyboard in [keyboardWindow subviews]) {
// Check to see if the description of the view we have referenced is UIKeyboard.
// If so then we found the keyboard view that we were looking for.
if([[keyboard description] hasPrefix:@"<UIKeyboard"] == YES) {
NSValue *v = [[notification userInfo] valueForKey:UIKeyboardBoundsUserInfoKey];
CGRect kbBounds = [v CGRectValue];
if(keyboardToolbar == nil) {
keyboardToolbar = [[UIToolbar alloc] initWithFrame:CGRectZero];
keyboardToolbar.barStyle = UIBarStyleBlackTranslucent;
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Dismiss" style:UIBarButtonItemStyleBordered target:self action:@selector(dismissKeyboard:)];
NSArray *items = [[NSArray alloc] initWithObjects:barButtonItem, nil];
[keyboardToolbar setItems:items];
[items release];
}
[keyboardToolbar removeFromSuperview];
keyboardToolbar.frame = CGRectMake(0, 0, kbBounds.size.width, 30);
[keyboard addSubview:keyboardToolbar];
keyboard.bounds = CGRectMake(kbBounds.origin.x, kbBounds.origin.y, kbBounds.size.width, kbBounds.size.height + 60);
for(UIView* subKeyboard in [keyboard subviews]) {
if([[subKeyboard description] hasPrefix:@"<UIKeyboardImpl"] == YES) {
subKeyboard.bounds = CGRectMake(kbBounds.origin.x, kbBounds.origin.y - 30, kbBounds.size.width, kbBounds.size.height);
}
}
}
}
}
}
|
|
|
04-21-2009, 06:41 PM
|
#13 (permalink)
|
|
New Member
Join Date: Apr 2009
Posts: 2
|
followup question
Excuse my noob question, but I'm trying out your code, and xcode says keyboardToolbar is undeclared when I compile... what should it be declared as?
|
|
|
06-01-2009, 08:17 PM
|
#14 (permalink)
|
|
New Member
Join Date: Apr 2009
Posts: 3
|
Maybe I'm doing something wrong but with the code above, I have noticed that it adds multiple toolbars one over the other and soon enough the Dismiss button doesn't work. If I use it on one tab view then it's fine but the problem is I use it on muliple tabs which is why it keeps adding I think. If anyone knows how to resolve this, please share.
Last edited by meridius; 06-02-2009 at 06:36 AM.
|
|
|
07-07-2009, 08:08 AM
|
#15 (permalink)
|
|
New Member
Join Date: Jan 2009
Posts: 2
|
Toolbar(TextField) on Keyboard Revisited
Having not visited this topic in quite some time here is a brief update...
This code is working in my demo to this point. I setup a Messages type app for educational purposes. Table datasource and delegates not provided. Obviously the messages array isn't provided either.
Notes based on comments:
1.) You have to make sure you don't keep stacking controls on top of the keyboard. As you can see in keyboardDidHide method that I remove the text field from the keyboard and apply it back to the bottom of the tableview. And vice versa when when the keyboard is called again.
2.) Obviously this is not all the code but enough to make it work. Types are implied by what is being instantiated. If there is no type defined obviously it's defined in the header.
3.) IMPORTANT! Have not checked the code for memory leaks. Use at your own discretion.
Code:
@synthesize tableView;
@synthesize textField;
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.separatorColor = [UIColor clearColor];
self.tableView.backgroundColor = [UIColor colorWithRed:(0xDD/255.0) green:(0xE2/255.0) blue:(0xEB/255.0) alpha:1.0];
self.view.backgroundColor = [UIColor colorWithRed:(0xDD/255.0) green:(0xE2/255.0) blue:(0xEB/255.0) alpha:1.0];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:self.view.window];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:self.view.window];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:self.view.window];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:self.view.window];
}
const int TEXTFIELD_HEIGHT = 30;
- (void) viewWillAppear:(BOOL)animated {
if(self.textField == nil) {
self.textField = [[KeyboardTextField alloc] initWithFrame:CGRectZero];
self.textField.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"border.png"]];
self.textField.delegate = self;
self.textField.returnKeyType = UIReturnKeySend;
[self.view addSubview:self.textField];
self.textField.frame = CGRectMake(0, self.view.frame.size.height - TEXTFIELD_HEIGHT, self.view.frame.size.width, TEXTFIELD_HEIGHT);
}
NSString *dummyData = [[NSBundle mainBundle] pathForResource:@"dummy" ofType:@"plist"];
messages = [[NSArray arrayWithContentsOfFile:dummyData] retain];
if(messages.count > 0) {
NSDictionary* dictionary = [messages objectAtIndex:0];
self.title = [dictionary objectForKey:@"sender"];
}
[self.tableView reloadData]; // manually sync datasource so we can scroll to the bottom
}
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self scrollToBottom];
}
- (void)keyboardWillShow:(NSNotification *)notification {
for (UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows]) {
// Now iterating over each subview of the available windows
for (UIView *keyboard in [keyboardWindow subviews]) {
// Check to see if the description of the view we have referenced is UIKeyboard.
// If so then we found the keyboard view that we were looking for.
if([[keyboard description] hasPrefix:@"<UIKeyboard"] == YES) {
NSValue *v = [[notification userInfo] valueForKey:UIKeyboardBoundsUserInfoKey];
CGRect kbBounds = [v CGRectValue];
keyboard.bounds = CGRectMake(kbBounds.origin.x, kbBounds.origin.y, kbBounds.size.width, kbBounds.size.height + (TEXTFIELD_HEIGHT * 2));
textField.frame = CGRectMake(0, 0, kbBounds.size.width, TEXTFIELD_HEIGHT);
[textField removeFromSuperview];
[keyboard addSubview:textField];
for(UIView* subKeyboard in [keyboard subviews]) {
if([[subKeyboard description] hasPrefix:@"<UIKeyboardImpl"] == YES) {
keyboardBounds = CGRectMake(kbBounds.origin.x, kbBounds.origin.y - TEXTFIELD_HEIGHT, kbBounds.size.width, kbBounds.size.height);
subKeyboard.bounds = keyboardBounds;
}
}
}
}
}
}
- (void)keyboardDidShow:(NSNotification*)notification {
self.tableView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - keyboardBounds.size.height - TEXTFIELD_HEIGHT);
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:messages.count - 1 inSection:0];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
- (void)keyboardWillHide:(NSNotification*)notification {
textField.text = nil;
}
- (void)keyboardDidHide:(NSNotification*)notification {
[textField removeFromSuperview];
textField.text = nil;
[self.view addSubview:textField];
textField.frame = CGRectMake(0, self.view.frame.size.height - TEXTFIELD_HEIGHT, textField.frame.size.width, textField.frame.size.height);
self.tableView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - TEXTFIELD_HEIGHT);
[self scrollToBottom];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[self.textField resignFirstResponder];
return NO;
}
- (void) scrollToBottom {
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:messages.count - 1 inSection:0];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
|
|
|
07-27-2009, 11:54 AM
|
#16 (permalink)
|
|
Registered Member
Join Date: Feb 2009
Location: India
Posts: 125
|
Thanks guys..... this thread is really helpful 
-John
|
|
|
07-30-2009, 07:48 AM
|
#17 (permalink)
|
|
I'll build your app!
Join Date: Feb 2009
Location: United States
Posts: 404
|
Can someone post the xcode project for this please.
Thanks,
Chase
|
|
|
08-01-2009, 08:51 AM
|
#18 (permalink)
|
|
Registered Member
Join Date: Feb 2009
Location: India
Posts: 125
|
Here is the link to the implementation..... I have used this logic to my forms and added next and previous button too..... Add Tool bar to keyboard
While working on this method further I came across some issue, I had som textfields where I dont want the toolbar,there also i am getting the keyboard with the toolbar. It seems once created it is not going away. Ny idea how to do fix this issue?
-John
Last edited by JohnMabassa; 08-05-2009 at 07:51 AM.
|
|
|
08-10-2009, 02:16 AM
|
#19 (permalink)
|
|
Registered Member
Join Date: Feb 2009
Location: India
Posts: 125
|
Quote:
Originally Posted by JohnMabassa
Here is the link to the implementation..... I have used this logic to my forms and added next and previous button too..... Add Tool bar to keyboard
While working on this method further I came across some issue, I had som textfields where I dont want the toolbar,there also i am getting the keyboard with the toolbar. It seems once created it is not going away. Ny idea how to do fix this issue?
-John
|
Any ideas on the above problem?
|
|
|
08-11-2009, 04:56 AM
|
#20 (permalink)
|
|
Registered Member
Join Date: May 2009
Posts: 17
|
Quote:
Originally Posted by JohnMabassa
Any ideas on the above problem?
|
Have the same problem
|
|
|
09-08-2009, 03:22 AM
|
#21 (permalink)
|
|
Registered Member
Join Date: Aug 2009
Posts: 51
|
Quote:
Originally Posted by meeper
Have the same problem 
|
it seems the easiest way in my head would be to make a BOOL = YES whenever one of your textFields is pressed.
under the didStartEditing (if that's what it's called, I forget) make your BOOL yes.
then surround all your code to show the toolbar with an if clause...
keyboardDidShow {
if (myBOOL == YES) {
//do all your code to show the toolbar here
}
}
under didFinishEditing (or whatever it's called) make your BOOL no.
i'll quite possible be trying something very similar quite soon, so i'll post some code example if i do.
if somebody beats me to it, please post your code here!
cheerio,
tim
|
|
|
12-17-2009, 01:26 PM
|
#22 (permalink)
|
|
Registered Member
Join Date: Dec 2009
Posts: 6
|
Hello mates
I know it's a quite old thread...
But I'm having the same problem of Meeper and JohnMabassa...and the code that ziph~~ shared isn't working for me >.>
Can someone help???
|
|
|
01-21-2010, 04:44 AM
|
#23 (permalink)
|
|
Registered Member
Join Date: Jul 2009
Posts: 29
|
hi
I am using both textview and text field in single view controller.
Toolbar is showing fine upon keyboard when clicking in textview but when clicking text field again toolbar is showing upon keyboard. but i don't want toolbar in case of text field.
this is my code
- (void)keyboardWillShow  NSNotification *)notification
{
for (UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows]) {
// Now iterating over each subview of the available windows
for (UIView *keyboard in [keyboardWindow subviews]) {
// Check to see if the description of the view we have referenced is UIKeyboard.
// If so then we found the keyboard view that we were looking for.
if([[keyboard description] hasPrefix:@"<UIKeyboard"] == YES) {
NSValue *v = [[notification userInfo] valueForKey:UIKeyboardBoundsUserInfoKey];
CGRect kbBounds = [v CGRectValue];
mKeyboardToolbar.barStyle = UIBarStyleBlackOpaque;
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemD one
target:self action:@selector(dismissKeyboard)];
UIBarButtonItem *flex = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemF lexibleSpace target:nil action:nil];
NSArray *items = [[NSArray alloc] initWithObjects:flex, barButtonItem, nil];
[mKeyboardToolbar setItems:items];
[items release];
[barButtonItem release];
[flex release];
[mKeyboardToolbar removeFromSuperview];
mKeyboardToolbar.frame = CGRectMake(0, 0, kbBounds.size.width, 50);
[keyboard addSubview:mKeyboardToolbar];
if(textField)
mKeyboardToolbar.hidden = YES;
else
mKeyboardToolbar.hidden = NO;
keyboard.bounds = CGRectMake(kbBounds.origin.x, kbBounds.origin.y , kbBounds.size.width, kbBounds.size.height + 100);
for(UIView* subKeyboard in [keyboard subviews]) {
if([[subKeyboard description] hasPrefix:@"<UIKeyboardImpl"] == YES) {
subKeyboard.bounds = CGRectMake(kbBounds.origin.x, kbBounds.origin.y -50, kbBounds.size.width, kbBounds.size.height);
}
}
}
}
}
}
|
|
|
 |
| Thread Tools |
|
|
| Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
|
» Advertisements |
» Online Users: 479 |
| 43 members and 436 guests |
| Alexman, andrei_c, BadgerDev, beit, benoitr007, boopyman, bravetarget, CHV, dave1619, Elegy, Eric 54, fede, firearasi, georgeburns, harrytheshark, HemiMG, ieasyproductions, iFizzgig, iisword, isley, Janek2004, jaywright00, jhaynie, jriskin, Lukapple80, muallin, myPhone, nobre84, peejavery, rdominelli, Rossco, rybek, Stan Edge, stlau, svjim, swnymor, taac16, Tambourin, Thaurin, TheKernal, tychop |
| Most users ever online was 779, 05-11-2009 at 09:55 AM. |
» Stats |
Members: 24,130
Threads: 38,899
Posts: 170,660
Top Poster: smasher (2,565)
|
| Welcome to our newest member, HunBirk427 |
|