How to calculate keyboard height in iOS? - ios

I know that this question is asked many times, but I can not figure out where am I making mistake. In simple words I can not implement it properly.
I have App which has to work on iPhone and iPad (in portrait orientation only). I have a subclassed UITextField. I need to move it up when it is hidden by keyboard during the edit.
I can not set it properly, because the calculation of the size of the keyboard is done after it enters in the edit mode.
I know that I need following steps:
Register observer
Have routine that calculates Keyboard rectangle from which I can take height
Have 2 events on show and hide of the keyboard to make offset of my custom text field.
Please tell me where I am wrong.
My code is:
Register observer:
- (id)initWithCoder:(NSCoder *)aDecoder{
if (self = [super initWithCoder:aDecoder]) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillChange:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillChange:) name:UIKeyboardDidShowNotification object:nil];
_leftInlineImage = NO;
}
return self;
}
Calculating keyboard height:
- (void)keyboardWillChange:(NSNotification *)notification {
NSDictionary* d = [notification userInfo];
CGRect r = [d[UIKeyboardFrameEndUserInfoKey] CGRectValue];
r = [self.superview convertRect:r fromView:nil];
_keyboardHeight = r.size.height;
}
Show/hide keyboard:
/* Move keyboard */
-(void)showKeyboardWithMove {
CGRect screenRect = [[UIScreen mainScreen] bounds];
////CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
//_keyboardHeight = KEYBOARD_HEIGHT;
if (self.frame.origin.y + self.frame.size.height > screenHeight - _keyboardHeight) {
double offset = screenHeight - _keyboardHeight - self.frame.origin.y - self.frame.size.height;
CGRect rect = CGRectMake(0, offset, self.superview.frame.size.width, self.superview.frame.size.height);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
self.superview.frame = rect;
[UIView commitAnimations];
}
}
-(void)hideKeyboardWithMove {
CGRect rect = CGRectMake(0, 0, self.superview.frame.size.width, self.superview.frame.size.height);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
self.superview.frame = rect;
[UIView commitAnimations];
}
The calculation is made before and my height is 0. All this is done in the subclass of the UITextField.

Add an observer of UIKeyboardWillChangeFrameNotification to the viewDidLoad;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardFrameDidChange:) name:UIKeyboardWillChangeFrameNotification object:nil];
This method will help you :
- (void)keyboardFrameDidChange:(NSNotification *)notification
{
CGRect keyboardEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect keyboardBeginFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
UIViewAnimationCurve animationCurve = [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];
NSTimeInterval animationDuration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] integerValue];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
CGRect newFrame = self.view.frame;
CGRect keyboardFrameEnd = [self.view convertRect:keyboardEndFrame toView:nil];
CGRect keyboardFrameBegin = [self.view convertRect:keyboardBeginFrame toView:nil];
newFrame.origin.y -= (keyboardFrameBegin.origin.y - keyboardFrameEnd.origin.y);
self.view.frame = newFrame;
[UIView commitAnimations];
}

that gives you back the height of the keyboard.
NSNotification * note = // ... the notification you receive via UIKeyboardWillShowNotification
id _obj = [note.userInfo valueForKey:#"UIKeyboardBoundsUserInfoKey"];
CGRect _keyboardBound = CGRectNull;
if ([_obj respondsToSelector:#selector(getValue:)]) [_obj getValue:&_keyboardBound];
the _keyboardBound will have the correct size.
NOTE: that is not a full implementation to handle the keyboard's appearance, if you need the complex idea, please check my complete and accepted answer here (stackoverflow.com internal link).

Related

About iOS10 animation

I'm coding a login view, when the keyboard show, background will move the same distance with an animation, but I find a question that I can't understand, when the animation begin, at the top of the background will display a white area, the white are is just the area that will disappear when the animation finished.
Here is my code
- (void)keyboardWillShow:(NSNotification *)notification{
CGRect keyboardBounds;
[[notification.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardBounds];
NSNumber * duration = [notification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSNumber * curve = [notification.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey];
keyboardBounds = [self.view convertRect:keyboardBounds toView:nil];
CGRect viewFrame = self.view.frame;
viewFrame.origin.y = 0 - keyboardBounds.size.height;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:[duration doubleValue]];
[UIView setAnimationCurve:[curve intValue]];
[UIView setAnimationDelegate:self];
self.bgView.frame = viewFrame;
[UIView commitAnimations];
}
Thanks in advance!

iOS move view above keyboard left black space

I am using a UIView with a button at the bottom of the view.
I want to move the button right above the keyboard when the keyboard shows / changes height.
The code I am using is:
- (void)keyboardFrameDidChange:(NSNotification *)notification
{
CGRect keyboardEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect keyboardBeginFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGRect newFrame = self.view.frame;
CGRect keyboardFrameEnd = [self.view convertRect:keyboardEndFrame toView:nil];
CGRect keyboardFrameBegin = [self.view convertRect:keyboardBeginFrame toView:nil];
newFrame.origin.y -= (keyboardFrameBegin.origin.y - keyboardFrameEnd.origin.y);
self.view.frame = newFrame;
}
and in viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardFrameDidChange:) name:UIKeyboardDidChangeFrameNotification object:nil];
this code works find on iPhone6, but if it is in iPhone 5 and using a Chinese keyboard there will be a black space:

How do you move a UITextField in response to the keyboard appearing and disappearing in iOS7?

How do you move a UITextField on the screen so that it is not covered by the keyboard in iOS7, and then return it to its original spot inside the UIView once the keyboard is dismissed?
in your Viewcontroller.h
#interface ViewController : UIViewController<UITextFieldDelegate>
{
CGFloat animatedDistance;
}
in ViewController.M
//paste the below 4 line in anywhere on the class (outside the method)
static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.3;
static const CGFloat MINIMUM_SCROLL_FRACTION = 0.2;
static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8;
static const CGFloat PORTRAIT_KEYBOARD_HEIGHT = 216;
in delegate methods are
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
CGRect textFieldRect =
[self.view.window convertRect:textField.bounds fromView:textField];
CGRect viewRect =
[self.view.window convertRect:self.view.bounds fromView:self.view];
CGFloat midline = textFieldRect.origin.y + 0.5 * textFieldRect.size.height;
CGFloat numerator =
midline - viewRect.origin.y
- MINIMUM_SCROLL_FRACTION * viewRect.size.height;
CGFloat denominator =
(MAXIMUM_SCROLL_FRACTION - MINIMUM_SCROLL_FRACTION)
* viewRect.size.height;
CGFloat heightFraction = numerator / denominator;
if (heightFraction < 0.0)
{
heightFraction = 0.0;
}
else if (heightFraction > 1.0)
{
heightFraction = 1.0;
}
animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);
CGRect viewFrame = self.view.frame;
viewFrame.origin.y -= animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
CGRect viewFrame = self.view.frame;
viewFrame.origin.y += animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
You have to catch the notification for UIKeyboardWillShowNotification and edit your frames to move the UITextField to the right place (for example by using [UIView animateWithDuration:(NSTimeInterval) animations:^(void)animations]).
Here is a sample...
In init, add an observer on UIKeyboardWillShowNotification :
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow) name:UIKeyboardWillShowNotification object:nil];
Then add the - keyboardWillShow method to update your view (supposing _textfield is the name of your UITextField) :
- (void)keyboardWillShow {
NSLog(#"Show Keyboard");
[UIView animateWithDuration:.2 animations:^{
[_textField setFrame:_textField.frame];
[_textField setFrame:CGRectMake(_textfield.frame.origin.x, _textfield.frame.origin.y - 240, _textfield.frame.size.width, _textfield.frame.size.height)];
}];
}
You can use the UIKeyboardWillShowNotification notification to perform the inverse action.
I recommend to use a UIScrollView to move your content up, when the keyboard is shown.
Also Apple discourages us from using self defined constants for the keyboardsize: Other Languages may have different sizes. The correct size is embedded in the userInfo of the Notification:
Get the notifications for keyboard changes :
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillBeShown:)
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
Remember to remove the observer like:
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
These methods handle the keyboard changes:
- (void)keyboardWillBeShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGRect kbRect = [self.view.window convertRect:[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue] fromView:self.scrollView];
CGSize kbSize = kbRect.size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
}
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
NSTimeInterval duration = [info[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:duration animations:^{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
}];
}
Of course you could also manipulate the frame of the UITextView with these methods.

contentInset being ignored in ios7 for UIScrollView

This worked before ios7 when someone tapped on anything that could become first responder inside a UIScrollView. Now it does not - UITextFields/Views still can show under the keyboard.
Code:
- (void)keyboardWasShown:(NSNotification*)notification{
//Some similar questions mentioned this might work, but made no difference for me
self.automaticallyAdjustsScrollViewInsets=NO;
NSDictionary* info = [notification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
float height = 0.0;
if (UIDeviceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
height = kbSize.width;
} else {
height = kbSize.height;
}
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, height, 0.0);
[UIView animateWithDuration:.25
delay:0
options:(UIViewAnimationOptionAllowUserInteraction)
animations:^
{
self.editorScrollView.contentInset = contentInsets;
self.editorScrollView.scrollIndicatorInsets = contentInsets;
}
completion:^(BOOL finished)
{
}];
}
Currently, with this code nothing takes place when a uitextfield/view is assigned first responder status. The insets don't seem to change - I perhaps could use contentOffset but I would have to find the origin view's Y who just become first responder to do that.
Like I said, before ios7 this code worked (no textfield/view would be hidden behind the keyboard when assigned first responder status). I seem to be missing something obvious or perhaps there is a better way of doing this in ios7?
A better way to detect keyboard changing and frame.
The key point is to convert keyboard frame: CGRect keyboardFrameInsideView = [self.view convertRect:keyboardFrame fromView:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardFrameWillChange:)
name:UIKeyboardWillShowNotification
object:nil];
- (void)keyboardFrameWillChange:(NSNotification *)notification
{
CGRect keyboardFrame;
[[notification.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrame];
CGRect keyboardFrameInsideView = [self.view convertRect:keyboardFrame fromView:nil];
CGRect r = self.bodyView.frame;
r.size.height = CGRectGetMinY(keyboardFrameInsideView) - r.origin.y;
self.bodyView.frame = r;
}

keyboard is hiding the text field in IOS [duplicate]

This question already has answers here:
How can I make a UITextField move up when the keyboard is present - on starting to edit?
(98 answers)
Closed 9 years ago.
I have created a form in IOS using scrollview with some text fields. the view looks like this,
When I begin to edit either state or below fields, the keyboard hides that field. like this,
what should i do to see the below fields (i.e., state and below)??
You can try this code
Add following code at top of your viewcontroller.m file
static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.3;
static const CGFloat MINIMUM_SCROLL_FRACTION = 0.2;
static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8;
static const CGFloat PORTRAIT_KEYBOARD_HEIGHT = 216;
static const CGFloat LANDSCAPE_KEYBOARD_HEIGHT = 162;
CGFloat animatedDistance;
Inside textFieldShouldBeginEditing
-(BOOL) textFieldShouldBeginEditing:(UITextField*)textField
{
CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
CGRect viewRect = [self.view.window convertRect:self.view.bounds fromView:self.view];
CGFloat midline = textFieldRect.origin.y + 0.5 * textFieldRect.size.height;
CGFloat numerator = midline - viewRect.origin.y - MINIMUM_SCROLL_FRACTION * viewRect.size.height;
CGFloat denominator = (MAXIMUM_SCROLL_FRACTION - MINIMUM_SCROLL_FRACTION)
* viewRect.size.height;
CGFloat heightFraction = numerator / denominator;
if (heightFraction < 0.0)
{
heightFraction = 0.0;
}
else if (heightFraction > 1.0)
{
heightFraction = 1.0;
}
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationPortrait ||
orientation == UIInterfaceOrientationPortraitUpsideDown)
{
animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);
}
else
{
animatedDistance = floor(LANDSCAPE_KEYBOARD_HEIGHT * heightFraction);
}
CGRect viewFrame = self.view.frame;
viewFrame.origin.y -= animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
return YES;
}
Inside textFieldShouldEndEditing
- (BOOL) textFieldShouldEndEditing:(UITextField*)textField
{
CGRect viewFrame = self.view.frame;
viewFrame.origin.y += animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
You should definitely search for this in stack-overflow itself, before posting a question. Anyways, you can find the answer here.
Conform to protocol UITextFieldDelegate
Have a BOOL variable moved to signal, whether your view is moved or not.
Then implement the delegate methods.
-(void)textFieldDidBeginEditing:(UITextField *)textField {
if(!moved) {
[self animateViewToPosition:self.view directionUP:YES];
moved = YES;
}
}
-(void)textFieldDidEndEditing:(UITextField *)textField {
[textField resignFirstResponder];
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
if(moved) {
[self animateViewToPosition:self.view directionUP:NO];
}
moved = NO;
return YES;
}
-(void)animateViewToPosition:(UIView *)viewToMove directionUP:(BOOL)up {
const int movementDistance = -60; // tweak as needed
const float movementDuration = 0.3f; // tweak as needed
int movement = (up ? movementDistance : -movementDistance);
[UIView beginAnimations: #"animateTextField" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
viewToMove.frame = CGRectOffset(viewToMove.frame, 0, movement);
[UIView commitAnimations];
}
You need to use TPAvoidingKeyBoard Library into your app your problem is solved..
https://github.com/michaeltyson/TPKeyboardAvoiding
See this link. Download this project and add it into your project.
Then first you have to add scrollview to your view and then all your textfield into that scrollview add that TPAvoidingScrollView To Custom Class.
Your code is good. but you have to change UIScrollView y position instead of height. I have change your code and update. please update this
step 1: In the ViewDidLoad method of your class set up to listen for messages about the keyboard:
// Listen for keyboard appearances and disappearances
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardDidHide:)
name:UIKeyboardDidHideNotification
object:nil];
step 2: up/down your scrollview by implementing selector methods in same class
- (void)keyboardDidShow: (NSNotification *) notif{
//Keyboard becomes visible
scrollView.frame = CGRectMake(scrollView.frame.origin.x,
scrollView.frame.origin.y - 220,
scrollView.frame.size.width,
scrollView.frame.size.height); //move up
}
- (void)keyboardDidHide: (NSNotification *) notif{
//keyboard will hide
scrollView.frame = CGRectMake(scrollView.frame.origin.x,
scrollView.frame.origin.y + 220,
scrollView.frame.size.width,
scrollView.frame.size.height); //move down
}
Try this code
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if(textField==tfLocation)
{
[self.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y-50, self.view.frame.size.width, self.view.frame.size.height)];
}
return YES;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self.view setFrame:CGRectMake(self.view.frame.origin.x, 0, self.view.frame.size.width, self.view.frame.size.height)];
}

Resources