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?
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;
}
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?
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.
You can also try another library, it's called TPKeyboardAvoiding. It is working great, and is very easy to setup:
Add a UIScrollView into your view controller's xib
Set the scroll view's class to TPKeyboardAvoidingScrollView (still
in the xib, via the identity inspector)
Place all your controls within that scrollview
It also automatically hooks up "Next" buttons on the keyboard to switch through the text fields.
Related
I am very junior mobile programmer .I need to move up text views when keyboard appears.I follows this move-uiview-up-when-the-keyboard-appears-in-ios and it works well but I have a background image and I do not want to move up background image .so all textboxes are embed in UIView named as customView.I tried to move up customView instead of self.view .When I start enter in first textview, the customView moves up.But when I move to second textview,customview moves down to original position and textView become under the keyboard.customView need to stay move up the when i start enter in second textview .I really appreciate any help!.
#property (strong, nonatomic) IBOutlet UIView *customView;
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
return YES; }
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
[self.view endEditing:YES];
return YES; }
- (void)keyboardDidShow:(NSNotification *)notification
{
//Assign new frame to your view
[self.customView setFrame:CGRectMake(0,50,320,460)];
}
-(void)keyboardDidHide:(NSNotification *)notification
{
[self.customView setFrame:CGRectMake(0,193,320,460)];
}
Add the observer in viewDidLoad for best approach.
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillBeHidden:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification*)aNotification {
[UIView animateWithDuration:0.25 animations:^
{
CGRect newFrame = [customView frame];
newFrame.origin.y -= 50; // tweak here to adjust the moving position
[customView setFrame:newFrame];
}completion:^(BOOL finished)
{
}];
}
- (void)keyboardWillBeHidden:(NSNotification*)aNotification {
[UIView animateWithDuration:0.25 animations:^
{
CGRect newFrame = [customView frame];
newFrame.origin.y += 50; // tweak here to adjust the moving position
[customView setFrame:newFrame];
}completion:^(BOOL finished)
{
}];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.view endEditing:YES];
}
// Add a scrollview on main view and add UITextField on that scrollview
-(void) viewDidLoad
{
UIScrollView *myScrollView = [[UIScrollView alloc] initWithFrame:[UIScreen mainScreen].bounds];
myScrollView.contentSize = CGSizeMake(320, 500);
myScrollView.contentInset = UIEdgeInsetsMake(0, 0, 60, 0);
[self.view addSubview:myScrollView];
UITextField *myTextField = [[UITextField alloc] initWithFrame:CGRectMake(20,30,100,33)];
[myScrollView addSubview:myTextField];
myTextField.delegate = self;
}
// Set the scrollview content offset to make the myTextField move up
- (void) textFieldDidBeginEditing:(UITextField *)textField
{
[myScrollView setContentOffset:CGPointMake(0,textField.center.y-80) animated:YES];
// here '80' can be any number which decide the height that textfiled should move
}
//To move the textfield to its original position
- (BOOL) textFieldShouldReturn:(UITextField *)textField
{
[[myScrollView setContentOffset:CGPointMake(0,0) animated:YES];
[textField resignFirstResponder];
return YES;
}
Make your class implement the UITextFieldDelegate.
Put the following code in viewDidLoad.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillBeHidden:) name:UIKeyboardWillHideNotification object:nil];
And define the following functions in your .m file.
- (void)keyboardWasShown:(NSNotification *)aNotification
{// scroll to the text view
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] 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 app might not need or want this behavior.
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.height;
self.scrollView.scrollEnabled = YES;
if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {
[self.scrollView scrollRectToVisible:activeField.frame animated:YES];
}
}
- (void)keyboardWillBeHidden:(NSNotification *)aNotification
{
// scroll back..
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
self.scrollView.scrollEnabled = NO;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
activeField = textField;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
activeField = nil;
}
Is there some way to get UIKeyboard size programmatically. 216.0f height and 162.0f height in landscape.
Following seem to be deprecated. Is there some way that works without any warning in both 3.0 iPhone OS SDK and 4.0 iPhone OS SDK to do this..
CGSize keyBoardSize = [[[note userInfo]
objectForKey:UIKeyboardBoundsUserInfoKey] CGRectValue].size;
You can get the keyboard size from the userInfo dictionary using the UIKeyboardFrameBeginUserInfoKey and the UIKeyboardFrameEndUserInfoKey instead.
These two keys return a NSValue instance containing a CGRect that holds the position and size of the keyboard at both the start and end points of the keyboard's show/hide animation.
Edit:
To clarify, the userInfo dictionary comes from an NSNotification instance. It's passed to your method that you register with an observer. For example,
- (void)someMethodWhereYouSetUpYourObserver
{
// This could be in an init method.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(myNotificationMethod:)
name:UIKeyboardDidShowNotification
object:nil];
}
- (void)myNotificationMethod:(NSNotification*)notification
{
NSDictionary* keyboardInfo = [notification userInfo];
NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameBeginUserInfoKey];
CGRect keyboardFrameBeginRect = [keyboardFrameBegin CGRectValue];
}
Edit 2:
Also, please don't forget to remove yourself as an observer in your dealloc method! This is to avoid a crash that would occur when the notification center tries to notify your object after its been freed.
You should use the UIKeyboardWillChangeFrameNotification instead, because some international keyboards, like the Chinese keyboard, will change frames during use. Also make sure to convert the CGRect into the proper view, for landscape use.
//some method like viewDidLoad, where you set up your observer.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillChange:) name:UIKeyboardWillChangeFrameNotification object:nil];
- (void)keyboardWillChange:(NSNotification *)notification {
CGRect keyboardRect = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
keyboardRect = [self.view convertRect:keyboardRect fromView:nil]; //this is it!
}
Here's how I finally made works. I combined suggestions and codes from different answers.
Features: dismissing keyboard, moving text fields above keyboard while editing and setting "Next" and "Done" keyboard return type.REPLACE "..." with more fields
static const CGFloat ANIMATION_DURATION = 0.4;
static const CGFloat LITTLE_SPACE = 5;
CGFloat animatedDistance;
CGSize keyboardSize;
#interface ViewController () <UITextFieldDelegate>
#property (weak, nonatomic) IBOutlet UITextField *firstNameTXT;
.....// some other text fields
#property (weak, nonatomic) IBOutlet UITextField *emailTXT;
#end
#implementation ViewController
- (void)viewDidLoad{
.....
// add tap gesture to help in dismissing keyboard
UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(tapScreen:)];// outside textfields
[self.view addGestureRecognizer:tapGesture];
// set text fields return key type to Next, last text field to Done
[self.firstNameTXT setReturnKeyType:UIReturnKeyNext];
.....
[self.emailTXT setReturnKeyType:UIReturnKeyDone];
// set text fields tags
[self.firstNameTXT setTag:0];
....// more text fields
[self.emailTXT setTag:5];
// add keyboard notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
}
// dismiss keyboard when tap outside text fields
- (IBAction)tapScreen:(UITapGestureRecognizer *)sender {
if([self.firstNameTXT isFirstResponder])[self.firstNameTXT resignFirstResponder];
...
if([self.emailTXT isFirstResponder])[self.emailTXT resignFirstResponder];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
if(textField.returnKeyType==UIReturnKeyNext) {
// find the text field with next tag
UIView *next = [[textField superview] viewWithTag:textField.tag+1];
[next becomeFirstResponder];
} else if (textField.returnKeyType==UIReturnKeyDone || textField.returnKeyType==UIReturnKeyDefault) {
[textField resignFirstResponder];
}
return YES;
}
// Moving current text field above keyboard
-(BOOL) textFieldShouldBeginEditing:(UITextField*)textField{
CGRect viewFrame = self.view.frame;
CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
CGRect viewRect = [self.view.window convertRect:self.view.bounds fromView:self.view];
CGFloat textFieldBottomLine = textFieldRect.origin.y + textFieldRect.size.height + LITTLE_SPACE;//
CGFloat keyboardHeight = keyboardSize.height;
BOOL isTextFieldHidden = textFieldBottomLine > (viewRect.size.height - keyboardHeight)? TRUE :FALSE;
if (isTextFieldHidden) {
animatedDistance = textFieldBottomLine - (viewRect.size.height - keyboardHeight) ;
viewFrame.origin.y -= animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
return YES;
}
-(void) restoreViewFrameOrigionYToZero{
CGRect viewFrame = self.view.frame;
if (viewFrame.origin.y != 0) {
viewFrame.origin.y = 0;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
}
-(void)keyboardDidShow:(NSNotification*)aNotification{
NSDictionary* info = [aNotification userInfo];
keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
}
-(void)keyboardDidHide:(NSNotification*)aNotification{
[self restoreViewFrameOrigionYToZero];// keyboard is dismissed, restore frame view to its zero origin
}
#end
On swift 4
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(getInfo(notif:)), name: .UIKeyboardDidShow , object: nil)
}
and then:
#objc func getInfo(notif: NSNotification) -> Void {
guard let userInfo = notif.userInfo else {return}
if let myData = userInfo["UIKeyboardFrameBeginUserInfoKey"] as? CGRect {
print(myData.width)
print(myData.height)
}
}
I'm trying to create a simple modal view controller that lets you edit text using a text view. However, when I present the view controller modally, it slides in from the bottom left direction instead of just sliding in from the bottom.
Here's a video of the weird effect: http://youtu.be/9M_MHA5mt1M
My controller simply watches for the keyboard to show and then resizes the text view using auto layout appropriately. Here's the code:
#import "TextPicker.h"
#interface TextPicker ()
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *keyboardHeight;
#end
#implementation TextPicker
- (id)initWithText:(NSString *)text
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil];
self = [storyboard instantiateViewControllerWithIdentifier:#"textPicker"];
if (self) {
self.text = text;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self observeKeyboard];
//self.textView.text = self.text;
[self.textView becomeFirstResponder];
}
- (void) viewWillDisappear:(BOOL)animated {
[self.textView resignFirstResponder];
}
- (IBAction)savePressed:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)cancelPressed:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void) dealloc {
[self stopObervingKeyboard];
}
- (void)observeKeyboard {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillChangeFrameNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)stopObervingKeyboard {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillChangeFrameNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
NSDictionary *info = [notification userInfo];
NSValue *kbFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
CGRect keyboardFrame = [kbFrame CGRectValue];
self.keyboardHeight.constant = -keyboardFrame.size.height;
NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:animationDuration animations:^{
[self.view layoutIfNeeded];
}];
}
- (void)keyboardWillHide:(NSNotification *)notification {
NSDictionary *info = [notification userInfo];
NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
self.keyboardHeight.constant = 0;
[UIView animateWithDuration:animationDuration animations:^{
[self.view layoutIfNeeded];
}];
}
- (IBAction)dismissKeyboard:(id)sender {
[self.textView resignFirstResponder];
}
#end
Your view is animating as you have asked it to by wrapping the [self.view layoutIfNeeded] call inside an animation block.
In viewDidLoad you begin observing keyboard changes, and when you detect them you animate the adjustments, this is normally correct. But then, before the view does its first layout, you show the keyboard; this results in an animation for all the views from CGRectZero to their proper sizes. And this is the effect you are seeing.
So basically you need to give the view a chance to layout before your animated layoutIfNeeded call. Probably the easiest way to do this is simply to move [self.textView becomeFirstResponder]; to either viewWillAppear: or viewDidAppear:.
*As a side note, remember to call super in appearance calls. I noticed you did not call [super viewWillDisappear];.
I am using UITableView, where each cell contains a UITextField, and using Apple official example, I wish to perform goal, moving the active field above the keyboard if it's already hidden. However, the form doesn't move although the UITableView is scroll eabled. Here is my relevant code, please help me pointing on what seems to be missing/wrong:
#interface ViewController (){
UITextField *activeField;
}
- (void)viewDidLoad
{
//....
objTableView.scrollEnabled=YES;
//....
}
#pragma mark - Keyboard notifications
// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification 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:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
objTableView.contentInset = contentInsets;
objTableView.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;
if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {
CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y-kbSize.height);
[objTableView setContentOffset:scrollPoint animated:YES];
}
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
objTableView.contentInset = contentInsets;
objTableView.scrollIndicatorInsets = contentInsets;
}
#pragma mark - UITextFieldDelegate protocol method
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
activeField = textField;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
activeField = nil;
}
Try this code:
if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {
CGRect rc = [activeField bounds];
rc = [activeField convertRect:rc toView:objTableView];
[objTableView scrollRectToVisible:rc animated:YES];
}
Is there some way to get UIKeyboard size programmatically. 216.0f height and 162.0f height in landscape.
Following seem to be deprecated. Is there some way that works without any warning in both 3.0 iPhone OS SDK and 4.0 iPhone OS SDK to do this..
CGSize keyBoardSize = [[[note userInfo]
objectForKey:UIKeyboardBoundsUserInfoKey] CGRectValue].size;
You can get the keyboard size from the userInfo dictionary using the UIKeyboardFrameBeginUserInfoKey and the UIKeyboardFrameEndUserInfoKey instead.
These two keys return a NSValue instance containing a CGRect that holds the position and size of the keyboard at both the start and end points of the keyboard's show/hide animation.
Edit:
To clarify, the userInfo dictionary comes from an NSNotification instance. It's passed to your method that you register with an observer. For example,
- (void)someMethodWhereYouSetUpYourObserver
{
// This could be in an init method.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(myNotificationMethod:)
name:UIKeyboardDidShowNotification
object:nil];
}
- (void)myNotificationMethod:(NSNotification*)notification
{
NSDictionary* keyboardInfo = [notification userInfo];
NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameBeginUserInfoKey];
CGRect keyboardFrameBeginRect = [keyboardFrameBegin CGRectValue];
}
Edit 2:
Also, please don't forget to remove yourself as an observer in your dealloc method! This is to avoid a crash that would occur when the notification center tries to notify your object after its been freed.
You should use the UIKeyboardWillChangeFrameNotification instead, because some international keyboards, like the Chinese keyboard, will change frames during use. Also make sure to convert the CGRect into the proper view, for landscape use.
//some method like viewDidLoad, where you set up your observer.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillChange:) name:UIKeyboardWillChangeFrameNotification object:nil];
- (void)keyboardWillChange:(NSNotification *)notification {
CGRect keyboardRect = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
keyboardRect = [self.view convertRect:keyboardRect fromView:nil]; //this is it!
}
Here's how I finally made works. I combined suggestions and codes from different answers.
Features: dismissing keyboard, moving text fields above keyboard while editing and setting "Next" and "Done" keyboard return type.REPLACE "..." with more fields
static const CGFloat ANIMATION_DURATION = 0.4;
static const CGFloat LITTLE_SPACE = 5;
CGFloat animatedDistance;
CGSize keyboardSize;
#interface ViewController () <UITextFieldDelegate>
#property (weak, nonatomic) IBOutlet UITextField *firstNameTXT;
.....// some other text fields
#property (weak, nonatomic) IBOutlet UITextField *emailTXT;
#end
#implementation ViewController
- (void)viewDidLoad{
.....
// add tap gesture to help in dismissing keyboard
UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(tapScreen:)];// outside textfields
[self.view addGestureRecognizer:tapGesture];
// set text fields return key type to Next, last text field to Done
[self.firstNameTXT setReturnKeyType:UIReturnKeyNext];
.....
[self.emailTXT setReturnKeyType:UIReturnKeyDone];
// set text fields tags
[self.firstNameTXT setTag:0];
....// more text fields
[self.emailTXT setTag:5];
// add keyboard notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
}
// dismiss keyboard when tap outside text fields
- (IBAction)tapScreen:(UITapGestureRecognizer *)sender {
if([self.firstNameTXT isFirstResponder])[self.firstNameTXT resignFirstResponder];
...
if([self.emailTXT isFirstResponder])[self.emailTXT resignFirstResponder];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
if(textField.returnKeyType==UIReturnKeyNext) {
// find the text field with next tag
UIView *next = [[textField superview] viewWithTag:textField.tag+1];
[next becomeFirstResponder];
} else if (textField.returnKeyType==UIReturnKeyDone || textField.returnKeyType==UIReturnKeyDefault) {
[textField resignFirstResponder];
}
return YES;
}
// Moving current text field above keyboard
-(BOOL) textFieldShouldBeginEditing:(UITextField*)textField{
CGRect viewFrame = self.view.frame;
CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
CGRect viewRect = [self.view.window convertRect:self.view.bounds fromView:self.view];
CGFloat textFieldBottomLine = textFieldRect.origin.y + textFieldRect.size.height + LITTLE_SPACE;//
CGFloat keyboardHeight = keyboardSize.height;
BOOL isTextFieldHidden = textFieldBottomLine > (viewRect.size.height - keyboardHeight)? TRUE :FALSE;
if (isTextFieldHidden) {
animatedDistance = textFieldBottomLine - (viewRect.size.height - keyboardHeight) ;
viewFrame.origin.y -= animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
return YES;
}
-(void) restoreViewFrameOrigionYToZero{
CGRect viewFrame = self.view.frame;
if (viewFrame.origin.y != 0) {
viewFrame.origin.y = 0;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
}
-(void)keyboardDidShow:(NSNotification*)aNotification{
NSDictionary* info = [aNotification userInfo];
keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
}
-(void)keyboardDidHide:(NSNotification*)aNotification{
[self restoreViewFrameOrigionYToZero];// keyboard is dismissed, restore frame view to its zero origin
}
#end
On swift 4
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(getInfo(notif:)), name: .UIKeyboardDidShow , object: nil)
}
and then:
#objc func getInfo(notif: NSNotification) -> Void {
guard let userInfo = notif.userInfo else {return}
if let myData = userInfo["UIKeyboardFrameBeginUserInfoKey"] as? CGRect {
print(myData.width)
print(myData.height)
}
}