UIKeyboardBoundsUserInfoKey is deprecated, what to use instead? - ios
I'm working on an iPad app using 3.2 sdk. I'm dealing with obtaining the keyboard size to prevent my textfields from hidding behind it.
I'm getting a Warning in Xcode -> UIKeyboardBoundsUserInfoKey is deprecated what should I use instead not to get this warning?
I played with the previously offered solution but still had issues. Here's what I came up with instead:
- (void)keyboardWillShow:(NSNotification *)aNotification {
[self moveTextViewForKeyboard:aNotification up:YES];
}
- (void)keyboardWillHide:(NSNotification *)aNotification {
[self moveTextViewForKeyboard:aNotification up:NO];
}
- (void) moveTextViewForKeyboard:(NSNotification*)aNotification up: (BOOL) up{
NSDictionary* userInfo = [aNotification userInfo];
// Get animation info from userInfo
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
// Animate up or down
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
CGRect newFrame = textView.frame;
CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];
newFrame.origin.y -= keyboardFrame.size.height * (up? 1 : -1);
textView.frame = newFrame;
[UIView commitAnimations];
}
From the documentation for UIKeyboardBoundsUserInfoKey:
The key for an NSValue object containing a CGRect that identifies the bounds rectangle of the keyboard in window coordinates. This value is sufficient for obtaining the size of the keyboard. If you want to get the origin of the keyboard on the screen (before or after animation) use the values obtained from the user info dictionary through the UIKeyboardCenterBeginUserInfoKey or UIKeyboardCenterEndUserInfoKey constants. Use the UIKeyboardFrameBeginUserInfoKey or UIKeyboardFrameEndUserInfoKey key instead.
Apple recommends implementing a convenience routine such as this (which could be implemented as a category addition to UIScreen):
+ (CGRect) convertRect:(CGRect)rect toView:(UIView *)view {
UIWindow *window = [view isKindOfClass:[UIWindow class]] ? (UIWindow *) view : [view window];
return [view convertRect:[window convertRect:rect fromWindow:nil] fromView:nil];
}
to recover window-adjusted keyboard frame size properties.
I took a different approach, which involves checking the device orientation:
CGRect _keyboardEndFrame;
[[notification.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue:&_keyboardEndFrame];
CGFloat _keyboardHeight = ([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait || [[UIDevice currentDevice] orientation] == UIDeviceOrientationPortraitUpsideDown) ? _keyboardEndFrame.size.height : _keyboardEndFrame.size.width;
You simply use this code:
//NSVale *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
//instead of Upper line we can use either next line or nextest line.
//NSValue *aValue = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
NSValue *aValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey];
The following code fixes an issue in Jay's answer, which assumes that UIKeyboardWillShowNotification will not fire again when the keyboard is already present.
When typing with the Japanese/Chinese keyboard, iOS fires an extra UIKeyboardWillShowNotification with the new keyboard frame even though the keyboard is already present, leading to the height of the self.textView being reduced a second time in the original code.
This reduces self.textView to almost nothing. It then becomes impossible to recover from this problem since we will only expect a single UIKeyboardWillHideNotification the next time the keyboard is dismissed.
Instead of subtracting/adding height to self.textView depending on whether the keyboard is shown/hidden as in the original code, the following code just calculates the maximum possible height for self.textView after subtracting the height of the keyboard on screen.
This assumes that self.textView is suppose to fill the entire view of the view controller, and there's no other subview that needs to be visible.
- (void)resizeTextViewWithKeyboardNotification:(NSNotification*)notif {
NSDictionary* userInfo = [notif userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardFrameInWindowsCoordinates;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindowsCoordinates];
[self resizeTextViewToAccommodateKeyboardFrame:keyboardFrameInWindowsCoordinates
withAnimationDuration:animationDuration
animationCurve:animationCurve];
}
- (void)resizeTextViewToAccommodateKeyboardFrame:(CGRect)keyboardFrameInWindowsCoordinates
withAnimationDuration:(NSTimeInterval)duration
animationCurve:(UIViewAnimationCurve)curve
{
CGRect fullFrame = self.view.frame;
CGRect keyboardFrameInViewCoordinates =
[self.view convertRect:keyboardFrameInWindowsCoordinates fromView:nil];
// Frame of the keyboard that intersects with the view. When keyboard is
// dismissed, the keyboard frame still has width/height, although the origin
// keeps the keyboard out of the screen.
CGRect keyboardFrameVisibleOnScreen =
CGRectIntersection(fullFrame, keyboardFrameInViewCoordinates);
// Max frame availble for text view. Assign it to the full frame first
CGRect newTextViewFrame = fullFrame;
// Deduct the the height of any keyboard that's visible on screen from
// the height of the text view
newTextViewFrame.size.height -= keyboardFrameVisibleOnScreen.size.height;
if (duration)
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
[UIView setAnimationCurve:curve];
}
// Adjust the size of the text view to the new one
self.textView.frame = newTextViewFrame;
if (duration)
{
[UIView commitAnimations];
}
}
Also, don't forget to register the keyboard notifications in viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
NSNotificationCenter* notifCenter = [NSNotificationCenter defaultCenter];
[notifCenter addObserver:self selector:#selector(resizeTextViewWithKeyboardNotification:) name:UIKeyboardWillShowNotification object:nil];
[notifCenter addObserver:self selector:#selector(resizeTextViewWithKeyboardNotification:) name:UIKeyboardWillHideNotification object:nil];
}
About splitting the resizing code into two parts
The reason why the textView resizing code is split into two parts (resizeTextViewWithKeyboardNotification: and resizeViewToAccommodateKeyboardFrame:withAnimationDuration:animationCurve:) is to fix another issue when the keyboard persists through a push from one view controller to another (see How do I detect the iOS keyboard when it stays up between controllers?).
Since the keyboard is already present before the view controller is pushed, there's no additional keyboard notifications being generated by iOS, and thus no way to resize the textView based on those keyboard notifications.
The above code (as well as the original code) that resizes self.textView will thus only work when the keyboard is shown after the view has been loaded.
My solution is to create a singleton that stores the last keyboard coordinates, and on - viewDidAppear: of the viewController, call:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Resize the view if there's any keyboard presence before this
// Only call in viewDidAppear as we are unable to convertRect properly
// before view is shown
[self resizeViewToAccommodateKeyboardFrame:[[UASKeyboard sharedKeyboard] keyboardFrame]
withAnimationDuration:0
animationCurve:0];
}
UASKeyboard is my singleton here. Ideally we should call this in - viewWillAppear:, however in my experience (at least on iOS 6), the convertRect:fromView: method that we need to use in resizeViewToAccommodateKeyboardFrame:withAnimationDuration:animationCurve: does not properly convert the keyboard frame to the view coordinates before the view is fully visible.
Just use the UIKeyboardFrameBeginUserInfoKey or UIKeyboardFrameEndUserInfoKey key instead of UIKeyboardBoundsUserInfoKey
#Jason, you code if fine except for one point.
At the moment you are not actually animating anything and the view will simply `pop' to its new size.height.
You have to specify a state from which to animate. An animation is a sort of (from state)->(to state) thing.
Luckily there is a very convenient method to specify the current state of the view as the (from state).
[UIView setAnimationBeginsFromCurrentState:YES];
If you add that line right after beginAnimations:context: your code works perfectly.
- (CGSize)keyboardSize:(NSNotification *)aNotification {
NSDictionary *info = [aNotification userInfo];
NSValue *beginValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey];
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
CGSize keyboardSize;
if ([UIKeyboardDidShowNotification isEqualToString:[aNotification name]]) {
_screenOrientation = orientation;
if (UIDeviceOrientationIsPortrait(orientation)) {
keyboardSize = [beginValue CGRectValue].size;
} else {
keyboardSize.height = [beginValue CGRectValue].size.width;
keyboardSize.width = [beginValue CGRectValue].size.height;
}
} else if ([UIKeyboardDidHideNotification isEqualToString:[aNotification name]]) {
// We didn't rotate
if (_screenOrientation == orientation) {
if (UIDeviceOrientationIsPortrait(orientation)) {
keyboardSize = [beginValue CGRectValue].size;
} else {
keyboardSize.height = [beginValue CGRectValue].size.width;
keyboardSize.width = [beginValue CGRectValue].size.height;
}
// We rotated
} else if (UIDeviceOrientationIsPortrait(orientation)) {
keyboardSize.height = [beginValue CGRectValue].size.width;
keyboardSize.width = [beginValue CGRectValue].size.height;
} else {
keyboardSize = [beginValue CGRectValue].size;
}
}
return keyboardSize;
}
Here is a good details
http://i-phone-dev.blogspot.com/2012/01/different-way-to-show-keyboard-and.html
Its worked like this
This is the constraint of the save button bottom
#IBOutlet weak var saveBtnBottom: NSLayoutConstraint!
#IBOutlet weak var nameText: UITextField!
Inside viewDidLoad
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
nameText.delegate = self
This is the functions we need
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
nameText.resignFirstResponder()
return true
}
#objc func keyBoardWillShow(notification: Notification){
if let userInfo = notification.userInfo as? Dictionary<String, AnyObject>{
let frame = userInfo[UIResponder.keyboardFrameEndUserInfoKey]
let keyBoardRect = frame?.cgRectValue
if let keyBoardHeight = keyBoardRect?.height {
self.saveBtnBottom.constant = keyBoardHeight
UIView.animate(withDuration: 0.5, animations: {
self.view.layoutIfNeeded()
})
}
}
}
#objc func keyBoardWillHide(notification: Notification){
self.saveBtnBottom.constant = 30.0
UIView.animate(withDuration: 0.5, animations: {
self.view.layoutIfNeeded()
})
}
Related
Is it possible to create inputAccessoryView above the keyboard for the full width of the screen in the split mode?
Is it possible to create inputAccessoryView above the keyboard for the full width of the screen in the split mode? System automatically resizes it to fit to the app frame. Is it a bug in iOS?
You can use this method to detect if your keyboard is in split mode. Note: In order for this to work you need a UITextField/UITextView with a non-nil inputAccessoryView (you can just use an empty view for that). NSArray *classPath = #[ #"KeyboardAutomatic", #"KeyboardImpl", #"KeyboardLayoutStar", #"KBKeyplaneView", #"KBSplitImageView" ]; UIView *splitView = textField.inputAccessoryView.superview; for (NSString *className in classPath) { for (UIView *subview in splitView.subviews) { if ([NSStringFromClass([subview class]) rangeOfString:className].location != NSNotFound) { splitView = subview; break; } } } BOOL isSplit = [splitView.subviews count] > 1; Then you could use a custom inputAccessoryView and edit it's CGRectFrame depending if the keyboard is in split mode or not. Here a good example: https://github.com/bmancini55/iOSExamples-DockedKeyboardView
Sharing accepted answer for same question Link UIKit posts UIKeyboardWillShowNotification when it shows the keyboard, and UIKeyboardWillHideNotification when it hides the keyboard. These notifications contain everything you need to properly animate your UITextField. Let's say your UITextField is in a property called called myTextField. First, you need to register for the notifications somewhere. Where you register depends on what object is responsible for moving myTextField. In my project, the field's superview is responsible, and since I load my UI from a nib, I do it in the superview's awakeFromNib: - (void)awakeFromNib { [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHideOrShow:) name:UIKeyboardWillHideNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHideOrShow:) name:UIKeyboardWillShowNotification object:nil]; } If you use a UIViewController to move the field around, you'll probably want to do it in viewWillAppear:animated:. You should unregister in your dealloc or viewWillDisappear:animated:: - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } Of course the tricky bit is in the keyboardWillHideOrShow: method. First I extract the animation parameters from the notification: - (void)keyboardWillHideOrShow:(NSNotification *)note { NSDictionary *userInfo = note.userInfo; NSTimeInterval duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; UIViewAnimationCurve curve = [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]; CGRect keyboardFrame = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; The keyboardFrame is in the global coordinate system. I need to convert the frame to the same coordinate system as myTextField.frame, and myTextField.frame is in the coordinate system of myTextField.superview: CGRect keyboardFrameForTextField = [self.myTextField.superview convertRect:keyboardFrame fromView:nil]; Next, I compute the frame that I want myTextField to move to. The bottom edge of the new frame should be equal to the top edge of the keyboard's frame: CGRect newTextFieldFrame = self.myTextField.frame; newTextFieldFrame.origin.y = keyboardFrameForTextField.origin.y - newTextFieldFrame.size.height; Finally, I animate myTextField to its new frame, using the same animation parameters that the keyboard is using: [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState | curve animations:^{ self.myTextField.frame = newTextFieldFrame; } completion:nil]; } Here it is all put together: - (void)keyboardWillHideOrShow:(NSNotification *)note { NSDictionary *userInfo = note.userInfo; NSTimeInterval duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; UIViewAnimationCurve curve = [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]; CGRect keyboardFrame = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; CGRect keyboardFrameForTextField = [self.myTextField.superview convertRect:keyboardFrame fromView:nil]; CGRect newTextFieldFrame = self.myTextField.frame; newTextFieldFrame.origin.y = keyboardFrameForTextField.origin.y - newTextFieldFrame.size.height; [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState | curve animations:^{ self.myTextField.frame = newTextFieldFrame; } completion:nil]; }
Move up keyboard when editing UITextField on iOS9
For my keyboards to move up to uncover UITextField in my iOS app, I used to implement this answer: https://stackoverflow.com/a/6908258/3855618 on iOS7 and 8 and it has worked perfectly for now. However on iOS 9.1, it doesn't work anymore. To be more accurate, even if the background view does move up, the UITextField doesn't. Any idea of what has changed so much since iOS9 and iOS 9.1?
The answer you have linked is not recommended. You should not set the view controller view's frame directly, especially not if you are using auto layout. Instead of changing the view's frame you should add a scrollview as a subview to the view, and adjust the content inset when the keyboard is shown or hidden. From the official apple doc: When asked to display the keyboard, the system slides it in from the bottom of the screen and positions it over your app’s content. Because it is placed on top of your content, it is possible for the keyboard to be placed on top of the text object that the user wanted to edit. When this happens, you must adjust your content so that the target object remains visible. Adjusting your content typically involves temporarily resizing one or more views and positioning them so that the text object remains visible. The simplest way to manage text objects with the keyboard is to embed them inside a UIScrollView object (or one of its subclasses like UITableView). When the keyboard is displayed, all you have to do is reset the content area of the scroll view and scroll the desired text object into position. Thus, in response to a UIKeyboardDidShowNotification, your handler method would do the following: Get the size of the keyboard. Adjust the bottom content inset of your scroll view by the keyboard height. Scroll the target text field into view. // 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); scrollView.contentInset = contentInsets; 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; if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) { [self.scrollView scrollRectToVisible:activeField.frame animated:YES]; } } // Called when the UIKeyboardWillHideNotification is sent - (void)keyboardWillBeHidden:(NSNotification*)aNotification { UIEdgeInsets contentInsets = UIEdgeInsetsZero; scrollView.contentInset = contentInsets; scrollView.scrollIndicatorInsets = contentInsets; }
Zero lines of Code Devoid of hacks, kludges, workaround and listeners. The present question has been asked over and over since the dawn of iOS time. No answer on StackOverflow survived more than 2 iOS iterations. Rightly so, because the UIKit keeps changing from underneath your feet. There exists a design as opposed to implementation solution to this ancient problem. Use a UITableViewController. Use a UITableViewController When a UITableView is managed by a UITableViewController, the scrolling is managed automatically for you. Never tinker with UIKeyboardWillShowNotification, ever again. Merely create static or dynamic UITableViewCells to layout your interface, add UITextView or UITextField as needed ; merely becoming first responder will scroll the the proper location. #availability(iOS, introduced=2.0) Notes Works on all iOS since 2.0. Quote: «Waste no time optimizing a poor algorithm ; pick a better one» See https://stackoverflow.com/a/32390936/218152.
We need to take keyboard frame from notification. When get reference of scrollView, tableView, etc. Convert low border of view to window`s coordinates. When determine how much keyboard covers our view, and if difference is greater than 0, we can add inset below. Try this code: - (void)subscribeKeyboardNotifications { [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } - (void)unsubscribeKeyboardNotifications { [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } - (void)keyboardWillShow:(NSNotification *)aNotification { CGRect keyBoardFrame = [[[aNotification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; UIWindow *keyWindow = [[[UIApplication sharedApplication] delegate] window]; UIScrollView *someScrollView = ...... CGPoint tableViewBottomPoint = CGPointMake(0, CGRectGetMaxY([someScrollView bounds])); CGPoint convertedTableViewBottomPoint = [someScrollView convertPoint:tableViewBottomPoint toView:keyWindow]; CGFloat keyboardOverlappedSpaceHeight = convertedTableViewBottomPoint.y - keyBoardFrame.origin.y; if (keyboardOverlappedSpaceHeight > 0) { UIEdgeInsets tableViewInsets = UIEdgeInsetsMake(0, 0, keyboardOverlappedSpaceHeight, 0); [someScrollView setContentInset:tableViewInsets]; } } - (void)keyboardWillHide:(NSNotification *)aNotification { UIEdgeInsets tableViewInsets = UIEdgeInsetsZero; UIScrollView *someScrollView = ...... [someScrollView setContentInset:tableViewInsets]; }
Add all UITextField on UIScrollView and use TPKeyboardAvoiding
I'm usually listening to keyboard notifications and make according changes to layout constraints. See my other answer for more details and a sample project.
Try this code that I have used in my previous projects: - (void)textFieldDidBeginEditing:(UITextField *)textField { [self didBeginEditingIn:textField]; } - (void)textFieldDidEndEditing:(UITextField *)textField { [self didEndEditing]; } 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+100; static const CGFloat LANDSCAPE_KEYBOARD_HEIGHT = 162+100; - (void)didBeginEditingIn:(UIView *)view { CGRect textFieldRect = [self.view.window convertRect:view.bounds fromView:view]; 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]; } - (void)didEndEditing { 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]; }
i followed the doc from #Istvan to the apple site, and there are a lot of stuff missing to make it work: 1. Set your .h document to <UITextFieldDelegate> (to be able to work with "activefield") 2. In the viewDidLoad, set the delegates to your UITextfields, and set the height of your scrollview content with a bigger height (in my case i've setted 500 more): CGRect screenRect = [[UIScreen mainScreen] bounds]; CGFloat screenWidth = screenRect.size.width; CGFloat screenHeight = screenRect.size.height + 500; _scrollView.contentSize = CGSizeMake(screenWidth, screenHeight); And now it's all working...
Textview Frame is become squeez and cannot come back to its original form?
keyboardWillShow method implementation : - (void)keyboardWillShow:(NSNotification *)notification { [UIView beginAnimations:nil context:nil]; CGRect endRect = [[notification.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; CGRect newRect = txtNotes.frame; //Down size your text view newRect.size.height -= endRect.size.height; txtNotes.frame = newRect; [UIView commitAnimations]; } keyboardWillHide method implementation : - (void)keyboardWillHide:(NSNotification *)notification { // Resize your textview when keyboard is going to hide UIEdgeInsets contentInsets = UIEdgeInsetsZero; txtNotes.contentInset = contentInsets; txtNotes.scrollIndicatorInsets = contentInsets; }
Couple of things: 1) META: You should add 4 spaces before each of the code lines to get the code to display properly. 2) This looks like a basic constraints issue. You should examine the Auto Layout of your storyboard.
UITableView slightly goes up when keyboard hides
I am using UITableView (chatTable) along with UITabBar (chatTabBar) and one textField inside imageView. I am using autolayout. I used the following code to change the views when keyboard appears and disappears. - (void)keyboardWasShown:(NSNotification*)aNotification { NSDictionary* info = [aNotification userInfo]; // get animation info from userInfo NSTimeInterval animationDuration; CGRect keyboardFrame; [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration]; [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] getValue:&keyboardFrame]; // resize the frame [UIView animateWithDuration:animationDuration delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ self.keyboardHeight.constant = keyboardFrame.size.height - TABBAR_HEIGHT ; [self.view layoutIfNeeded]; } completion:nil]; if ([chatData count] != VALUE_ZERO) { [chatTable scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:([chatData count] - VALUE_ONE) inSection:VALUE_ZERO] atScrollPosition:UITableViewScrollPositionBottom animated:NO]; } } - (void)keyboardWillHide:(NSNotification*)aNotification { NSDictionary* info = [aNotification userInfo]; // get animation info from userInfo NSTimeInterval animationDuration; CGRect keyboardFrame; [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration]; [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] getValue:&keyboardFrame]; // Set view frame [UIView animateWithDuration:animationDuration delay:2.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ self.keyboardHeight.constant -= keyboardFrame.size.height - TABBAR_HEIGHT; [self.view layoutIfNeeded]; } completion:nil]; } Now when I press return the tableview goes up a littel bit (from screen 2 to screen 3). keyboardHeight is the bottom space constraint between the tabBar and main view. (screen 2) (screen3) I have tried many things but I can't able to find why the tableview is going up for a while. (problem is there is no smooth animation.) (Note: I have put delay as 2.0 only to show what happens in following screenshot(screen 3) othewise it's value would be 0)
Your problem is that you're changing the table view frame when the keyboard appears, which is wrong. You need to change the contentInset property of the table view, instead of meddling with frames. - (void)keyboardWillShow:(NSNotification *)notification { CGFloat height = [notification.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue].size.height - self.tabBarController.tabBar.frame.size.height; UIEdgeInsets edgeInsets = UIEdgeInsetsMake(0.0f, 0.0f, height, 0.0f); _tableView.contentInset = edgeInsets; _tableView.scrollIndicatorInsets = edgeInsets; } - (void)keyboardWillHide:(NSNotification *)notification { UIEdgeInsets edgeInsets = UIEdgeInsetsZero; _tableView.contentInset = edgeInsets; _tableView.scrollIndicatorInsets = edgeInsets; }
Solved the problem with contentInset property. I am using contentInset as mentiond by the #Eugene and also changing the constant property of bottom constraint of the textfiled to move up and doen whenever keyboard is shown and hidden.
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; }