Reputation: 19303
I trying to push my view up when the keyboard is showing (it overlays data I want the user to see while he's typing. I'm using this code:
KBKeyboardHandler.h:
@protocol KBKeyboardHandlerDelegate;
@interface KBKeyboardHandler : NSObject
- (id)init;
// Put 'weak' instead of 'assign' if you use ARC
@property(nonatomic, assign) id<KBKeyboardHandlerDelegate> delegate;
@property(nonatomic) CGRect frame;
@end
KBKeyboardHandler.m:
#import "KBKeyboardHandler.h"
#import "KBKeyboardHandlerDelegate.h"
@implementation KBKeyboardHandler
- (id)init
{
self = [super init];
if (self)
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
@synthesize delegate;
@synthesize frame;
- (void)keyboardWillShow:(NSNotification *)notification
{
CGRect oldFrame = self.frame;
[self retrieveFrameFromNotification:notification];
if (oldFrame.size.height != self.frame.size.height)
{
CGSize delta = CGSizeMake(self.frame.size.width - oldFrame.size.width,
self.frame.size.height - oldFrame.size.height);
if (self.delegate)
[self notifySizeChanged:delta notification:notification];
}
}
- (void)keyboardWillHide:(NSNotification *)notification
{
if (self.frame.size.height > 0.0)
{
[self retrieveFrameFromNotification:notification];
CGSize delta = CGSizeMake(-self.frame.size.width, -self.frame.size.height);
if (self.delegate)
[self notifySizeChanged:delta notification:notification];
}
self.frame = CGRectZero;
}
- (void)retrieveFrameFromNotification:(NSNotification *)notification
{
CGRect keyboardRect;
[[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardRect];
self.frame = [[UIApplication sharedApplication].keyWindow.rootViewController.view convertRect:keyboardRect fromView:nil];
}
- (void)notifySizeChanged:(CGSize)delta notification:(NSNotification *)notification
{
NSDictionary *info = [notification userInfo];
UIViewAnimationCurve curve;
[[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&curve];
NSTimeInterval duration;
[[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&duration];
void (^action)(void) = ^{
[self.delegate keyboardSizeChanged:delta];
};
[UIView animateWithDuration:duration
delay:0.0
options:curve
animations:action
completion:nil];
}
@end
KBKeyboardHandlerDelegate.h:
@protocol KBKeyboardHandlerDelegate
- (void)keyboardSizeChanged:(CGSize)delta;
@end
Sample MyViewController.h:
@interface MyViewController : UIViewController<KBKeyboardHandlerDelegate>
...
@end
Sample MyViewController.m:
@implementation MyViewController
{
KBKeyboardHandler *keyboard;
}
- (void)dealloc
{
keyboard.delegate = nil;
[keyboard release];
[super dealloc];
}
- (void)viewDidLoad
{
[super viewDidLoad];
keyboard = [[KBKeyboardHandler alloc] init];
keyboard.delegate = self;
}
- (void)viewDidUnload
{
[super viewDidUnload];
keyboard.delegate = nil;
[keyboard release];
keyboard = nil;
}
- (void)keyboardSizeChanged:(CGSize)delta
{
// Resize / reposition your views here. All actions performed here
// will appear animated.
// delta is the difference between the previous size of the keyboard
// and the new one.
// For instance when the keyboard is shown,
// delta may has width=768, height=264,
// when the keyboard is hidden: width=-768, height=-264.
// Use keyboard.frame.size to get the real keyboard size.
// Sample:
CGRect frame = self.view.frame;
frame.size.height -= delta.height;
self.view.frame = frame;
}
That I've found here. I'm trying to figure out why my view isn't pushing up. The keyboard is showing and keyboardSizeChanged
is fired up but the view doesn't move. I opened a new project and copied the KBKeyboardHandler and delegate files to it, implemented the code and in the new project it works fine so I know for a fact that it's something in my original project that is messed up. Any idea what it can be?
Upvotes: 3
Views: 749
Reputation: 376
You can also try another library, it's called TPKeyboardAvoiding. It is working great, and is very easy to setup:
It also automatically hooks up "Next" buttons on the keyboard to switch through the text fields.
Upvotes: 0
Reputation: 429
If you are not using a UITableView use UIScrollView as the parent view of your elements and add the code below Adjust as needed,
You will need a NSArray of NSObjects, I called mine scrollToObjects and in viewDidLoad add the elements to the array that would need scrolling so that when keyboardWasShown is called you can check to see if the currently selected element should be scrolled to.
I used self.activeField to store my currently selected element which is set when a element triggers an event(the event needs to be one of the first called and that is always called)
Then I check to see if the scrollToObjects contains activeField and if it does scroll the UIScrollView up and then back down when the activeField resignsFirstResponder
// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:) name:UIKeyboardWillHideNotification object:nil];
}
// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
// If active text field is hidden by keyboard, scroll it so it's visible
// Your application might not need or want this behavior.
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.height;
// Wouldn't go true so used an array that contains text fields that need to be scrolled to
// if (!CGRectContainsPoint(aRect, self.activeField.frame.origin) ) {
// CGPoint scrollPoint = CGPointMake(0.0, self.activeField.frame.origin.y- kbSize.height);
// [self.scrollView setContentOffset:scrollPoint animated:YES];
// }
if ([self.scrollToObjects containsObject:self.activeField]) {
CGPoint scrollPoint = CGPointMake(0.0, self.activeField.frame.origin.y+ (self.activeField.frame.size.height*2)-kbSize.height);
[self.scrollView setContentOffset:scrollPoint animated:YES];
}
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
// self.scrollView.contentInset = UIEdgeInsetsZero;
[self.scrollView setContentOffset:CGPointMake(0.0, 0.0) animated:YES];
self.scrollView.scrollIndicatorInsets = UIEdgeInsetsZero;
}
A simpler solution would be to handle the UITextFieldDelegate methods below with following code or something similar to activation and deactivation of the object
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
CGPoint scrollPoint = CGPointMake(0.0, textField.frame.origin.y);
[self.theScrollView setContentOffset:scrollPoint animated:YES];
}
-(void)textFieldDidEndEditing:(UITextField *)textField
{
[self.theScrollView setContentOffset:CGPointMake(0.0, 0.0) animated:YES];
self.theScrollView.scrollIndicatorInsets = UIEdgeInsetsZero;
}
Upvotes: 1
Reputation: 613
The problem is in keyboardSizeChanged: - what you want to adjust is frame.origin.y, not frame.size.height. At least that is what I wanted it to do.
Upvotes: 0
Reputation: 12902
I'd check your calculation for delta.
CGSize delta = CGSizeMake(self.frame.size.width - oldFrame.size.width,
self.frame.size.height - oldFrame.size.height);
My guess is oldFrame
and self.frame
might have the same dimensions.
I'm trying to think if there's anything else that could have been missed, like properly linking views to these objects or something in the interface editor?
Upvotes: 0