Obj-c - Wrong keyboard height is returned? - ios

I'm trying to get the height of the iOS keyboard so that I can move my view up when the keyboard is animated. However, I keep getting the value 258 returned (which, isn't correct, as it pushes my view up too high?) Why is this happening? Code below:
ViewController.m
-(void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillChange:) name:UIKeyboardWillChangeFrameNotification object:nil];
}
- (void)keyboardWillChange:(NSNotification *)notification {
NSDictionary* keyboardInfo = [notification userInfo];
NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameEndUserInfoKey];
CGRect keyboardFrameBeginRect = [keyboardFrameBegin CGRectValue];
self.keyboardHeight = keyboardFrameBeginRect.size.height;
}
- (void) animateTextView:(BOOL) up
{
const int movementDistance = self.keyboardHeight;
const float movementDuration = 0.3f;
int movement= movement = (up ? -movementDistance : movementDistance);
[UIView beginAnimations: #"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.upView.frame = CGRectOffset(self.upView.frame, 0, movement);
[UIView setAnimationDidStopSelector:#selector(afterAnimationStops)];
[UIView commitAnimations];
}

To get height of keyboard, you should use UIKeyboardWillShowNotification or UIKeyboardDidShowNotification instead of UIKeyboardWillChangeFrameNotification.
-(void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillChange:) name:UIKeyboardWillShowNotification object:nil];
}
If you use UITabBarController, you have to calculate frame without tab bar height. You can get tab bar height with the code below.
self.tabBarController.tabBar.frame.height

You should register UIKeyboardWillShowNotification for observing the keyboard height.
1) [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillChange:) name:UIKeyboardWillShowNotification object:nil];
2) you can also try this code :
(void)keyboardWillChange:(NSNotification *)notification
{
NSDictionary* keyboardInfo = [notification userInfo];
NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameBeginUserInfoKey];
CGRect keyboardFrameBeginRect = [keyboardFrameBegin CGRectValue];
}

Related

Move UIView up when keyboard appears

Ok so I have gone through almost all questions on SO and tutorials. I am now able to move my UIView up so that it is visible while typing. However the problem is, I want to move the UIView ONLY if the UITextField gets covered by the keyboard, because if it is not, then there is no point in moving the UIView. My code so far:
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
#pragma mark - keyboard movements
- (void)keyboardWillShow:(NSNotification *)notification
{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
[UIView animateWithDuration:0.3 animations:^{
CGRect f = self.view.frame;
f.origin.y = -keyboardSize.height;
self.view.frame = f;
}];
}
-(void)keyboardWillHide:(NSNotification *)notification
{
[UIView animateWithDuration:0.3 animations:^{
CGRect f = self.view.frame;
f.origin.y = 0.0f;
self.view.frame = f;
}];
}
Any help will be appreciated, thank you.
To check is UITextField covered by keyboard you can do something like this:
- (void)keyboardWillShow:(NSNotification *)notification {
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
if (myTextField.frame.origin.y + myTextField.frame.size.height > [UIScreen mainScreen].bounds.size.height - keyboardSize.height) {
// textfield is covered by keyboard
[UIView animateWithDuration:0.3 animations:^{
CGRect f = self.view.frame;
f.origin.y = -keyboardSize.height;
self.view.frame = f;
}];
}
}

Enable scrolling content when keyboard appears in iOS

I have an application on iPhone who has much content in viewcontroller. Generally the main content is form. My problem is that I put up keyboard and want to type some value to form fields much of content is invisible. I want to scroll this content when keyboard appear. How can I do this?
My view does'n have scroll view however I tried do this but it don't works.
All hints I found so far concern how to put up used textbox, but this is not my assumption.
This is what i did, I changed the top constraint when keyboard rises up and down like this-
in viewDidLoad call this method-
[self observeKeyboard];
#pragma mark- Keyboard Listen Methods
- (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)keyboardWillShow:(NSNotification *)notification {
NSDictionary *info = [notification userInfo];
NSValue *kbFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect keyboardFrame = [kbFrame CGRectValue];
CGFloat height = keyboardFrame.size.height;
self.COnstraintTopViewVertical.constant=(value of constant)-height;
[UIView animateWithDuration:animationDuration animations:^{
[self.view layoutIfNeeded];
}];
}
- (void)keyboardWillHide:(NSNotification *)notification {
NSDictionary *info = [notification userInfo];
NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
self.ConstraintTopViewVertical.constant=reset value;
[UIView animateWithDuration:animationDuration animations:^{
[self.view layoutIfNeeded];
}];
}
You can programmatically change position in the view upon keyboard appearance with the following code:
func keyboardWasShown(notification: NSNotification) {
UIView.animateWithDuration(0.3, animations: { () -> Void in
self.setContentOffset(CGPoint(x: setXOffsetHere, y: setYOffsetHere), animated: true)
})
}
This code will transition the view to the coordinates you specify in .setContentOffset call after keyboard appearance. You still have to get the coordinates, but usually they are pretty straightforward to get from storyboard.
Put all your views in a scroll view
Set an auto layout constraint from the bottom of the scroll view to the bottom of the superview
In viewWillAppear
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillChangeFrame:)
name:UIKeyboardWillChangeFrameNotification object:nil];
Handle the KB notification
- (void)keyboardWillChangeFrame:(NSNotification*)aNotification
{
CGRect kbFrame = [aNotification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect kbWindowIntersectionFrame = CGRectIntersection(self.view.window.bounds, kbFrame);
[UIView animateWithDuration:[aNotification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue] animations:^{
self.scrollVBottomConstraint.constant = kbWindowIntersectionFrame.size.height;
[self.view layoutIfNeeded];
}];
}
what i got from your question is: you are using textfield on UIView which is not on the scrollview, now you have to scroll the UIView when keyboard appears. just do following stuff.
-Give the tag to your textfield.
-suppose tag you have given is 4545646
-do not forgot to assign delegate to your textfield (it will execute below delegate method when you start to edit)
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
if (textField.tag == 4545646) {
UIView *contanerView = [self.view viewWithTag:5556466];
[UIView animateWithDuration:0.5 animations:^{
contanerView.frame = CGRectMake(self.view.frame.origin.x+1, -85, self.view.frame.size.width, self.view.frame.size.height-9);
}];
}
}
Change the frame as per your requirement.
and
- (void)textFieldDidEndEditing:(UITextField *)textField {
if (textField.tag == 4545646) {
[textField resignFirstResponder];
UIView *contanerView = [self.view viewWithTag:5556466];
[UIView animateWithDuration:0.5 animations:^{
contanerView.frame = CGRectMake(self.view.frame.origin.x+1, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height);
}];
}
In viewDidAppear add the following notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyBoardShown:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyBoardDismiss:) name:UIKeyboardWillHideNotification object:nil];
and in keyBoardShown method get the keyboard height
- (void)keyBoardShown:(NSNotification*)notification
{
if(self.view.frame.origin.y>=0)
{
NSDictionary* keyboardInfo = [notification userInfo];
NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameBeginUserInfoKey];
CGRect keyboardFrameBeginRect = [keyboardFrameBegin CGRectValue];
// NSLog(#"hihi : %f",keyboardFrameBeginRect.size.height);
keyBoardHeight = keyboardFrameBeginRect.size.height-yDeault+50;
if (keyBoardHeight>0) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
self.view.frame = CGRectMake(self.view.frame.origin.x, (self.view.frame.origin.y-keyBoardHeight), self.view.frame.size.width, self.view.frame.size.height);
[UIView commitAnimations];
}
}
}
in keyBoardDismiss setback the mainview y coordinate to previous value
-(void)keyBoardDismiss:(NSNotification*)notification{
if(self.view.frame.origin.y<0){
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
self.view.frame = CGRectMake(self.view.frame.origin.x, (self.view.frame.origin.y+keyBoardHeight), self.view.frame.size.width, self.view.frame.size.height);
[UIView commitAnimations];
}
}
here yDeault is textfield y coordinate value
yDeault= screenHeight-textField.frame.origin.y+textField.frame.size.height;
Once the keyboard is shown main view will be moved up and once keyboard is dismissed main view will be moved back to the original position
OK. I done this. I need to just add scroll view but in my app probably I have to reconstruct all my view.
No need to add scrollview. Directly you can do this. You can change the self.view.frame without the need of scrollview.

iOS Keyboard Delaying Animations

I'm currently trying to develop a chat feature for an iOS app. I've been playing around with the keyboard and everything seems to be working other than the animation.
When I press the keyboard the animation to move the view up is delayed by a second. I've made a video of it happening here.
My code is as follows:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
The selectors:
- (void)keyboardDidShow: (NSNotification *) notif{
NSDictionary *info = [notif userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
_currentKeyboardHeight = kbSize.height;
// Calculate free space between navigation bar and keyboard top to reposition the chat bubbles.
float areaHeight = screenHeight - (_currentKeyboardHeight + _footer.frame.size.height + 100);
if([Infrastructure_Connection ConnectivityCheck]){
[UIView animateWithDuration:0.2 delay:0 options:0 animations:^{
[_ChatBar setFrame:CGRectMake(posX, screenHeight-(_currentKeyboardHeight+height), width, height)];
bubbleTableMain.frame = CGRectMake(0,100, self.view.frame.size.width,areaHeight);
} completion:^(BOOL finished) {
[bubbleTableMain scrollBubbleViewToBottomAnimated:YES];
}];
} else {
[RegisterUser AlertMessage:#"Offline" Message:#"You're currently in offline mode."];
}
}
- (void)keyboardDidHide: (NSNotification *) notif{
int whereKeyboardEnds = self.view.frame.size.height-(195);
[UIView animateWithDuration:0.2 delay:0.0 options:0 animations:^{
bubbleTableMain.frame = CGRectMake(0,100, self.view.frame.size.width,whereKeyboardEnds);
[_ChatBar setFrame:CGRectMake(posX, 474, width, height)];
} completion:^(BOOL finished) { }];
}
The delays are on 0.0 and still it delays it by a second. Anyone have any idea as to how, for example, Whatsapp make their keyboard interaction so smooth and in time with the keyboard appearing?
=================== Edit ===================
So I've changed the following code and now for some reason, it doesn't run the animation. I've debugged it and it calls the selector correctly. But doesn't animate:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
and
- (void)keyboardWillShow:(NSNotification *)note {
UIViewAnimationCurve animationCurve = [[[note userInfo] valueForKey: UIKeyboardAnimationCurveUserInfoKey] intValue];
NSTimeInterval animationDuration = [[[note userInfo] valueForKey: UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView beginAnimations:nil context: nil];
[UIView setAnimationCurve:animationCurve];
[UIView setAnimationDuration:animationDuration];
[_ChatBar setFrame:CGRectMake(0, 10, _ChatBar.frame.size.width, _ChatBar.frame.size.height)];
[UIView commitAnimations];
}
You are using the keyboardDidShow notification which is called after the keyboard has finished its animation. Use the keyboardWillShow notification instead. That should do the trick.

iOS 8 keyboard hides my textview

I have a UIViewController presented using self.accountViewController.modalPresentationStyle = UIModalPresentationFormSheet; and now in iOS 8 the last UITextView is hidden from the keyboard when it will pushed up. How to avoid It?
#Oleg's solution is good but it doesn't take into consideration keyboard changes in size while its already showing.. also, he hardcoded the animation duration and a few other parameters. See my solution below:
Add an observer of UIKeyboardWillChangeFrameNotification to the viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardFrameWillChange:) name:UIKeyboardWillChangeFrameNotification object:nil];
And then add the method:
- (void)keyboardFrameWillChange:(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];
}
Don't forget to remove the keyboard observer in both viewDidUnload and in Dealloc.
Swift Version of #newton_guima's answer above incase anyone wants it.
Add observer of UIKeyboardWillChangeFrameNotification to viewDidLoad():
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardFrameWillChange:", name: UIKeyboardWillChangeFrameNotification, object: nil)
Then add this method:
func keyboardFrameWillChange(notification: NSNotification) {
let keyboardBeginFrame = (notification.userInfo! as NSDictionary).objectForKey(UIKeyboardFrameBeginUserInfoKey)!.CGRectValue
let keyboardEndFrame = (notification.userInfo! as NSDictionary).objectForKey(UIKeyboardFrameEndUserInfoKey)!.CGRectValue
let animationCurve = UIViewAnimationCurve(rawValue: (notification.userInfo! as NSDictionary).objectForKey(UIKeyboardAnimationCurveUserInfoKey)!.integerValue)
let animationDuration: NSTimeInterval = (notification.userInfo! as NSDictionary).objectForKey(UIKeyboardAnimationDurationUserInfoKey)!.doubleValue
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(animationDuration)
UIView.setAnimationCurve(animationCurve!)
var newFrame = self.view.frame
let keyboardFrameEnd = self.view.convertRect(keyboardEndFrame, toView: nil)
let keyboardFrameBegin = self.view.convertRect(keyboardBeginFrame, toView: nil)
newFrame.origin.y -= (keyboardFrameBegin.origin.y - keyboardFrameEnd.origin.y)
self.view.frame = newFrame;
UIView.commitAnimations()
}
Then remove the observer wherever you transition away from the view or in deinit:
NSNotificationCenter.defaultCenter().removeObserver(self)
For solving of you're problem you should change frame or constrain of the textview.
Small tip for you:
Use Notification to detect when keyboard will show or hide.
Sample of notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
And than change the one of the parameters that are mention above.
Example of changing of frame:
- (void)keyboardWillHide:(NSNotification *)notification
{
[self.view layoutIfNeeded];
[UIView animateWithDuration:0.2
animations:^{
[self setStartingFrame:self.commentsView.frame.size.height - commentViewOutlet_.frame.size.height - tabBarOffset_];
[self.view layoutIfNeeded];
}];
}

Shift UITextField and UITableView up when keyboard comes up

I have a view with 1. Navigation bar 2.UITableView 3. UITextView.
When I start to edit the textView, a keyboard comes up and I need to animate the TextView and TableView up. I've implemented: https://stackoverflow.com/a/8704371/1808179, but that animated the entire view up, covering the navigation bar.
I tried individually animating the textView like:
- (void)keyboardWillShow:(NSNotification*)notification
{
CGRect chatTextFieldFrame = CGRectMake(chatTextField.frame.origin.x,chatTextField.frame.origin.y-218,chatTextField.frame.size.width,chatTextField.frame.size.height);
[UIView animateWithDuration:0.5 animations:^{ chatTextField.frame = chatTextFieldFrame;}];
}
But it doesn't animate, and it won't synchronously animate alongside the TableView.
What is the best way to animate the tableView and textView up without overlaying the navigation bar?
I generally use the follow snippet when tackling this problem.
Using a UITableView (which is just a subclass of UIScrollView) you should set contentInsets rather then just changing the frame each time. This is especially much nicer in iOS7 with a translucent keyboard.
- (void)viewDidLoad;
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)dealloc;
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
#pragma mark - Keyboard Notifications
- (void)keyboardWillShow:(NSNotification *)notification;
{
NSDictionary *userInfo = [notification userInfo];
NSValue *keyboardBoundsValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
CGFloat keyboardHeight = [keyboardBoundsValue CGRectValue].size.height;
CGFloat duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
NSInteger animationCurve = [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];
UIEdgeInsets insets = [[self tableView] contentInset];
[UIView animateWithDuration:duration delay:0. options:animationCurve animations:^{
[[self tableView] setContentInset:UIEdgeInsetsMake(insets.top, insets.left, keyboardHeight, insets.right)];
[[self view] layoutIfNeeded];
} completion:nil];
}
- (void)keyboardWillHide:(NSNotification *)notification;
{
NSDictionary *userInfo = [notification userInfo];
CGFloat duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
NSInteger animationCurve = [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];
UIEdgeInsets insets = [[self tableView] contentInset];
[UIView animateWithDuration:duration delay:0. options:animationCurve animations:^{
[[self tableView] setContentInset:UIEdgeInsetsMake(insets.top, insets.left, 0., insets.right)];
[[self view] layoutIfNeeded];
} completion:nil];
}
If any are wondering, this is how I did it:
- (void)keyboardWillShow:(NSNotification*)notification
{
CGRect chatTableViewFrame = CGRectMake(0,65,320,chatTableView.frame.size.height-180);
[UIView animateWithDuration:0.3 animations:^{ chatTableView.frame = chatTableViewFrame;}];
CGRect chatTextFieldFrame = CGRectMake(chatTextField.frame.origin.x,chatTextField.frame.origin.y-170,chatTextField.frame.size.width,chatTextField.frame.size.height);
[UIView animateWithDuration:0.3 animations:^{ chatTextField.frame = chatTextFieldFrame;}];
[self.chatTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:self.chat.count-1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
And vice-versa for keyboardWillHide.
Write this line at desired events.
self.view.frame = [[UIScreen mainScreen] applicationFrame];

Resources