In several cases I want to add a toolbar to the top of the iPhone keyboard (as in iPhone Safari when you're navigating form elements, for example).
Currently I am specifying the toolbar's rectangle with constants but because other elements of the interface are in flux - toolbars and nav bars at the top of the screen - every time we make a minor interface change, the toolbar goes out of alignment.
Is there a way to programmatically determine the position of the keyboard in relation to the current view?
As of iOS 3.2 there's a new way to achieve this effect:
UITextFields and UITextViews have an inputAccessoryView property, which you can set to any view, that is automatically displayed above and animated with the keyboard.
Note that the view you use should neither be in the view hierarchy elsewhere, nor should you add it to some superview, this is done for you.
So basically:
In the init method:
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(keyboardWillShow:) name: UIKeyboardWillShowNotification object:nil];
[nc addObserver:self selector:#selector(keyboardWillHide:) name: UIKeyboardWillHideNotification object:nil];
And then have methods referred to above to adjust the position of the bar:
-(void) keyboardWillShow:(NSNotification *) note
{
CGRect r = bar.frame, t;
[[note.userInfo valueForKey:UIKeyboardBoundsUserInfoKey] getValue: &t];
r.origin.y -= t.size.height;
bar.frame = r;
}
Could make it pretty by animating the position change by wrapping it in
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
//...
[UIView commitAnimations];
This is based on the existing answer from tonklon - I'm just adding a code snippet that shows a semi transparent black toolbar on top of the keyboard, together with a "done" button on the right:
UIToolbar *toolbar = [[[UIToolbar alloc] init] autorelease];
[toolbar setBarStyle:UIBarStyleBlackTranslucent];
[toolbar sizeToFit];
UIBarButtonItem *flexButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
UIBarButtonItem *doneButton =[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(resignKeyboard)];
NSArray *itemsArray = [NSArray arrayWithObjects:flexButton, doneButton, nil];
[flexButton release];
[doneButton release];
[toolbar setItems:itemsArray];
[aTextField setInputAccessoryView:toolbar];
and the -resignKeyboard looks like:
-(void)resignKeyboard {
[aTextField resignFirstResponder];
}
If you register for keyboard notifications, ie UIKeyboardWillShowNotification UIKeyboardWillHideNotification, etc, the notification you receive will contain the bounds of the keyboard in the userInfo dict (UIKeyboardBoundsUserInfoKey).
See the UIWindow class reference.
In 3.0 and above you can get the animation duration and curve from the userInfo dictionary of the notifications.
for instance, to animate the size of the view to make room for the keyboard, register for the UIKeyboardWillShowNotification and do something like the following:
- (void)keyboardWillShow:(NSNotification *)notification
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
[UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
CGRect frame = self.view.frame;
frame.size.height -= [[[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey] CGRectValue].size.height;
self.view.frame = frame;
[UIView commitAnimations];
}
Do a similar animation for UIKeyboardWillHideNotification.
Create this method and call it on ViewWillLoad:
- (void) keyboardToolbarSetup
{
if(self.keyboardToolbar==nil)
{
self.keyboardToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 44)];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:#"Cancel" style:UIBarButtonItemStylePlain target:self action:#selector(anyAction)];
UIBarButtonItem *extraSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonItemStyleDone target:self action:#selector(anyOtherAction)];
NSArray *toolbarButtons = [[NSArray alloc]initWithObjects:cancelButton,extraSpace,doneButton, nil];
[self.keyboardToolbar setItems:toolbarButtons];
self.myTextView.inputAccessoryView=self.keyboardToolbar;
}
}
There's no way (AFAIK) to get the dimensions of the keyboard view. It is however constant, at least in every iPhone version so far.
If you calculate the toolbar position as an offset from the BOTTOM of your view, and take the size of your view into account, then you should not have to worry whether a navbar is present or not.
E.g.
#define KEYBOARD_HEIGHT 240 // example - can't remember the exact size
#define TOOLBAR_HEIGHT 30
toolBarRect.origin.y = viewRect.size.height - KEYBOARD_HEIGHT - TOOLBAR_HEIGHT;
// move toolbar either directly or with an animation
Instead of a define, you could easily create a keyboardHeight function that returns the size based on whether the keyboard is being displayed, and move this toolbar positioning into a separate function that reorganizes your layout.
Also it can depend on where you do this positioning as it's possible the size of your view may change between being loaded and shown based on your navbar setup. I believe the best place to do it would be in viewWillAppear.
Related
I have a UIDatePicker which is created programmatically (as the first-responder) when user taps a text-field on my view. This happens inside a for-loop, so I don't have the reference to this picker in my code. I also have a toolbar on top of the picker which is added as an inputAccessoryView to the picker. I have a Done button which resigns the first-responder. So far so good.
I want to add another button on the toolbar besides the Done button which will change the value of the picker. There is no UIDatePickerDelegate which will let me track the active picker.
I can always define class variables for each of my picker and thus save the references manually. But is there an easy way to do this where I can access the inputView from the inputAccessoryView directly?
this in some.h File
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
{
IBOutlet UIDatePicker *picker1;
IBOutlet UITextField *txtFld;
}
#property (nonatomic, retain) UIToolbar *keyboardToolbar;
#end
In some.m file
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
picker1=[[UIDatePicker alloc] initWithFrame:CGRectMake(0, 0, 320, 300)];//frames are just for demo
[txtFld setInputView:picker1];
}
- (void)keyboardWillShow:(NSNotification *)notification
{
if(keyboardToolbar == nil) {
keyboardToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 410, 320, 44)] ;
[keyboardToolbar setBarStyle:UIBarStyleBlackTranslucent];
[keyboardToolbar sizeToFit];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.4];
UIBarButtonItem *flexButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
UIBarButtonItem *doneButton1 =[[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonItemStyleDone target:self action:#selector(resignKeyboard)];
NSArray *itemsArray = [NSArray arrayWithObjects:flexButton,doneButton1, nil];
[keyboardToolbar setItems:itemsArray];
[txtFld setInputAccessoryView:keyboardToolbar];
[self.view addSubview:keyboardToolbar];
[UIView commitAnimations];
}
}
-(void)resignKeyboard {
[keyboardToolbar removeFromSuperview];
[txtFld resignFirstResponder];
///do nescessary date calculation here
}
I have a navigation controller (A) whose parent view controller (not visible) presents another navigation controller as modal form sheet (B).
Well I'm trying to figure out how to move the modal view controller up so fields aren't obscured by keyboard, but I'm not sure which view to listen to the keyboard notifications on, and hence should be responsible for moving the navigation controller (B).
As an additional issue, I'm not sure that I even can move a modal form sheet view controller. I tried changing its frame, but that didn't do anything.
The code inside (A) that presents (B) is here...
imageEditor.navigationItem.title = #"Photo Details Editor";
imageEditor.edgesForExtendedLayout = UIRectEdgeNone;
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:imageEditor];
navController.modalPresentationStyle = UIModalPresentationFormSheet;
navController.topViewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(imageEditorDone)];
navController.topViewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:#selector(imageEditorCancelled)];
navController.preferredContentSize = imageEditor.view.frame.size;
[self.parentViewController presentViewController:navController animated:YES completion:^(void){ }];
How do I proceed here?
Thanks.
Here is an example that I used awhile back, you can modify it to work for your case. Essentially I'm calculating the intersection of the keyboard and my view, and then animating the views y-axis up to compensate for the keyboard.
#pragma mark - Keyboard Event Responses
-(void)observeKeyboardNotifications {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(respondToKeyboardAppearanceNotification:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(respondToKeyboardDisappearanceNotification:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)respondToKeyboardAppearanceNotification:(NSNotification *)inNotification {
// Workaround to the invalid animation curve returned below (<< 16). Source: https://devforums.apple.com/message/878410#878410
NSUInteger tmpOption = [[inNotification.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];
CGRect tmpKeyboardBeginFrame = [[inNotification.userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGRect tmpKeyboardEndFrame = [[inNotification.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
if(fabs(tmpKeyboardBeginFrame.origin.y- tmpKeyboardEndFrame.origin.y) < 50) {
// iOS 9 fires this notification when the first responder changes even if the keyboard is present
// This check will stop the appearance block from firing if the keyboard isn't actually appearing
return;
}
CGFloat heightAdjustment = [self intersectionOfView:self keyboardRect:tmpKeyboardEndFrame].size.height;
self.alertCenterY.constant = -heightAdjustment;
[UIView animateWithDuration:[[inNotification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]
delay:0.0f
options:(tmpOption << 16)
animations:
^{
[self.containerView layoutIfNeeded];
}
completion:nil];
}
-(void)respondToKeyboardDisappearanceNotification:(NSNotification *)inNotification {
// Workaround to the invalid animation curve returned here (<< 16). Source: https://devforums.apple.com/message/878410#878410
NSUInteger tmpOption = [[inNotification.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];
self.alertCenterY.constant = 0;
[UIView animateWithDuration:[[inNotification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]
delay:0.0f
options:(tmpOption << 16)
animations:
^{
[self.containerView layoutIfNeeded];
}
completion:nil];
}
- (CGRect)intersectionOfView:(UIView *)inView keyboardRect:(CGRect)inKeyboardRect {
CGRect tmpSelfFrame = CGRectZero;
CGRect tmpKeyboardFrame = inKeyboardRect;
if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) {
// Infer the keyboard's position in landscape. As it's attached to the window, its frame is fixed in portrait.
tmpKeyboardFrame = CGRectMake(0, CGRectGetWidth([self.window frame]) - CGRectGetWidth(tmpKeyboardFrame), CGRectGetHeight(tmpKeyboardFrame), CGRectGetWidth(tmpKeyboardFrame));
tmpSelfFrame = inView.frame;
} else {
tmpSelfFrame = [self.window convertRect:inView.frame toView:self.window];
}
return CGRectIntersection(tmpKeyboardFrame, tmpSelfFrame);
}
Or you can try to wrap your imageEditor content into TPKeyboardAvoidingScrollView and get some rest.
It will automatically detect if any UIControl element became a first responder and offset itself to avoid overlapping.
I am programmatically adding a UISegmentedControl to a UINavigationController's toolbar (I am in a UITableViewController). I want the segmented control to look decent, not filling the entire bar. Also, I want it to rotate with the view and resize. This should be pretty easy but I think I'm missing something. I actually got it to work, but this is not clean code so I am hoping someone can tell me which settings/methods to use for a "proper" implementation.
Getter:
- (UISegmentedControl*)stockFilterSegmentedControl {
if (!_stockFilterSegmentedControl) {
_stockFilterSegmentedControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"All",#"Holdings", nil]];
[_stockFilterSegmentedControl addTarget:self action:#selector(stockFilterControlPressed:) forControlEvents:UIControlEventValueChanged];
_stockFilterSegmentedControl.selectedSegmentIndex = 0;
_stockFilterSegmentedControl.autoresizingMask = UIViewAutoresizingFlexibleHeight;
CGRect newFrame = _stockFilterSegmentedControl.frame;
newFrame.size.height = self.navigationController.toolbar.frame.size.height * .8;
_stockFilterSegmentedControl.frame = newFrame;
}
return _stockFilterSegmentedControl;
}
Where we insert it:
- (NSArray*)navFooterToolbarArray {
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:self.stockFilterSegmentedControl];
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
UIBarButtonItem *refresh = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:#selector(refresh:)];
return [NSArray arrayWithObjects:flexibleSpace, barButtonItem, flexibleSpace, refresh, nil];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.title = #"Stocks";
self.toolbarItems = [self navFooterToolbarArray];
}
And to make it work I had to add:
- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
NSLog(#"Did autorotate.");
CGRect newFrame = self.stockFilterSegmentedControl.frame;
newFrame.size.height = self.navigationController.toolbar.frame.size.height * .8;
self.stockFilterSegmentedControl.frame = newFrame;
}
What's the right way to do this?
Thanks,
Damien
The answer is actually really simple - you set the segmentedControlStyle on the segmented control to UISegmentedControlStyleBar and it will resize perfectly without any drama. Autoresizing masks work as expected.
Thanks,
Damien
All you should really need is something like:
_stockFilterSegmentedControl.frame = CGRectInset(self.navigationController.toolbar.bounds, 5, 5); //set to toolbar rect inset by 5 pixels
_stockFilterSegmentedControl.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
You then won't have to do anything when the view rotates, it should just automatically resize to fit because of the autoresizingMask.
I'm attaching a UIToolbar to my UITextView as its inputAccessoryView in order to add a button to dismiss the keyboard. This works great and it looks correct when the device is in portrait mode. But I'm having trouble figuring out how to resize the toolbar to the lower height used for toolbars when the device is in landscape mode.
I'm adding the toolbar in my text view's delegate's -textViewShouldBeginEditing: method:
if (!textView.inputAccessoryView) {
UIToolbar *keyboardBar = [[UIToolbar alloc] init];
keyboardBar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin;
keyboardBar.barStyle = UIBarStyleBlackTranslucent;
UIBarButtonItem *spaceItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(dismissKeyboard:)];
[keyboardBar setItems:[NSArray arrayWithObjects:spaceItem, doneButton, nil]];
[spaceItem release];
[doneButton release];
[keyboardBar sizeToFit];
textView.inputAccessoryView = keyboardBar;
[keyboardBar release];
}
I get strange behavior from this code in landscape mode, though. If I start editing in landscape mode, the toolbar has the landscape height but the Done button is drawn half off the screen. If I then rotate to Portrait mode, the Done button is drawn in the correct location, and it remains in the correct location when I rotate back to landscape mode.
If I start editing in portrait mode, the toolbar is drawn with portrait height, but the Done button is drawn in the correct location. If I then rotate to landscape mode, the toolbar remains portrait height, but the Done button is still drawn in the correct position at least.
Any suggestions for how to get this to resize when the device rotates? I'm really hoping there's a more automatic way than manually plugging in the height magic numbers in one of the view controller's rotation events.
That's a tough problem. I've solved this in the past by adjusting the frame when the accessory view gets laid out after rotating. Try something like this:
#interface RotatingTextInputToolbar : UIToolbar
#end
#implementation RotatingTextInputToolbar
- (void) layoutSubviews
{
[super layoutSubviews];
CGRect origFrame = self.frame;
[self sizeToFit];
CGRect newFrame = self.frame;
newFrame.origin.y += origFrame.size.height - newFrame.size.height;
self.frame = newFrame;
}
#end
And using the the RotatingTextInputToolbar instead of the UIToolbar in your code, above.
Voila:
#interface AccessoryToolbar : UIToolbar #end
#implementation AccessoryToolbar
-(id)init
{
if (self = [super init])
{
[self updateSize];
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(orientationDidChange:) name:UIApplicationDidChangeStatusBarOrientationNotification object:NULL];
}
return self;
}
-(void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
-(void)orientationDidChange:(NSNotification*)notification
{
[self updateSize];
}
-(void)updateSize
{
bool landscape = UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]);
CGSize size = UIScreen.mainScreen.bounds.size;
if (landscape != size.width > size.height)
std::swap(size.width, size.height);
if (size.height <= 320)
size.height = 32;
else
size.height = 44;
self.frame = CGRectMake(0, 0, size.width, size.height);
}
#end
In several cases I want to add a toolbar to the top of the iPhone keyboard (as in iPhone Safari when you're navigating form elements, for example).
Currently I am specifying the toolbar's rectangle with constants but because other elements of the interface are in flux - toolbars and nav bars at the top of the screen - every time we make a minor interface change, the toolbar goes out of alignment.
Is there a way to programmatically determine the position of the keyboard in relation to the current view?
As of iOS 3.2 there's a new way to achieve this effect:
UITextFields and UITextViews have an inputAccessoryView property, which you can set to any view, that is automatically displayed above and animated with the keyboard.
Note that the view you use should neither be in the view hierarchy elsewhere, nor should you add it to some superview, this is done for you.
So basically:
In the init method:
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(keyboardWillShow:) name: UIKeyboardWillShowNotification object:nil];
[nc addObserver:self selector:#selector(keyboardWillHide:) name: UIKeyboardWillHideNotification object:nil];
And then have methods referred to above to adjust the position of the bar:
-(void) keyboardWillShow:(NSNotification *) note
{
CGRect r = bar.frame, t;
[[note.userInfo valueForKey:UIKeyboardBoundsUserInfoKey] getValue: &t];
r.origin.y -= t.size.height;
bar.frame = r;
}
Could make it pretty by animating the position change by wrapping it in
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
//...
[UIView commitAnimations];
This is based on the existing answer from tonklon - I'm just adding a code snippet that shows a semi transparent black toolbar on top of the keyboard, together with a "done" button on the right:
UIToolbar *toolbar = [[[UIToolbar alloc] init] autorelease];
[toolbar setBarStyle:UIBarStyleBlackTranslucent];
[toolbar sizeToFit];
UIBarButtonItem *flexButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
UIBarButtonItem *doneButton =[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(resignKeyboard)];
NSArray *itemsArray = [NSArray arrayWithObjects:flexButton, doneButton, nil];
[flexButton release];
[doneButton release];
[toolbar setItems:itemsArray];
[aTextField setInputAccessoryView:toolbar];
and the -resignKeyboard looks like:
-(void)resignKeyboard {
[aTextField resignFirstResponder];
}
If you register for keyboard notifications, ie UIKeyboardWillShowNotification UIKeyboardWillHideNotification, etc, the notification you receive will contain the bounds of the keyboard in the userInfo dict (UIKeyboardBoundsUserInfoKey).
See the UIWindow class reference.
In 3.0 and above you can get the animation duration and curve from the userInfo dictionary of the notifications.
for instance, to animate the size of the view to make room for the keyboard, register for the UIKeyboardWillShowNotification and do something like the following:
- (void)keyboardWillShow:(NSNotification *)notification
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
[UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
CGRect frame = self.view.frame;
frame.size.height -= [[[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey] CGRectValue].size.height;
self.view.frame = frame;
[UIView commitAnimations];
}
Do a similar animation for UIKeyboardWillHideNotification.
Create this method and call it on ViewWillLoad:
- (void) keyboardToolbarSetup
{
if(self.keyboardToolbar==nil)
{
self.keyboardToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 44)];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:#"Cancel" style:UIBarButtonItemStylePlain target:self action:#selector(anyAction)];
UIBarButtonItem *extraSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonItemStyleDone target:self action:#selector(anyOtherAction)];
NSArray *toolbarButtons = [[NSArray alloc]initWithObjects:cancelButton,extraSpace,doneButton, nil];
[self.keyboardToolbar setItems:toolbarButtons];
self.myTextView.inputAccessoryView=self.keyboardToolbar;
}
}
There's no way (AFAIK) to get the dimensions of the keyboard view. It is however constant, at least in every iPhone version so far.
If you calculate the toolbar position as an offset from the BOTTOM of your view, and take the size of your view into account, then you should not have to worry whether a navbar is present or not.
E.g.
#define KEYBOARD_HEIGHT 240 // example - can't remember the exact size
#define TOOLBAR_HEIGHT 30
toolBarRect.origin.y = viewRect.size.height - KEYBOARD_HEIGHT - TOOLBAR_HEIGHT;
// move toolbar either directly or with an animation
Instead of a define, you could easily create a keyboardHeight function that returns the size based on whether the keyboard is being displayed, and move this toolbar positioning into a separate function that reorganizes your layout.
Also it can depend on where you do this positioning as it's possible the size of your view may change between being loaded and shown based on your navbar setup. I believe the best place to do it would be in viewWillAppear.