I have a UIViewController that contains a UITableView with custom cells, inside the cell are UILabels, a couple of uneditable UI
I fixed the issue. Please see my solution below:
1. First declare a global varibale called "activeFileld"
@property(nonatomic,strong)id activeFiled;
2. Create a method called "registerForKeyboardNotifications"
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification object:nil]; //Posted immediately prior to the display of the keyboard
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification object:nil]; //Posted immediately prior to the dismissal of the keyboard.
}
3. Called the above method in viewWillAppear:
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
//Register kryboard Notification
[self registerForKeyboardNotifications];
}
4. Call the Delegate method for UitextFieldd Or UitextView
- (void)textFieldDidBeginEditing:(UITextField *)sender {
self.activeField = sender;
}
- (void)textFieldDidEndEditing:(UITextField *)sender{
self.activeField = nil;
}
- (void)textViewDidBeginEditing:(UITextView *)textView
{
// save the text view that is being edited
_notes = textView.text;
}
- (void)textViewDidEndEditing:(UITextView *)textView
{
// release the selected text view as we don't need it anymore
_activeField = nil;
}
5.
- (void)keyboardWillShow:(NSNotification *)notification
{
if([_activeField isKindOfClass:[UITextField class]]) {
NSDictionary* info = [notification userInfo];
NSLog(@"Dictionary %@",info);
CGRect kbRect = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
kbRect = [self.view convertRect:kbRect fromView:nil];
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbRect.size.height, 0.0);
self.tableView.contentInset = contentInsets;
self.tableView.scrollIndicatorInsets = contentInsets;
CGRect aRect = self.view.frame;
aRect.size.height -= kbRect.size.height;
UITextField *textField = (UITextField*)_activeField;
if (!CGRectContainsPoint(aRect, textField.frame.origin) ) {
[self.tableView scrollRectToVisible:textField.frame animated:YES];
}
}else if([_activeField isKindOfClass:[UITextView class]]) {
NSDictionary* info = [notification userInfo];
NSLog(@"Dictionary %@",info);
CGRect kbRect = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
kbRect = [self.view convertRect:kbRect fromView:nil];
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbRect.size.height, 0.0);
self.tableView.contentInset = contentInsets;
self.tableView.scrollIndicatorInsets = contentInsets;
CGRect aRect = self.view.frame;
aRect.size.height += kbRect.size.height;
UITextView *activeTextView = (UITextView*)_activeField;
if (!CGRectContainsPoint(aRect, textField.superview.superview.frame.origin) ) {
[self.tableView scrollRectToVisible:activeTextView.superview.superview.frame animated:YES];
}
}
}
// Called when the UIKeyboardWillHideNotification is received
- (void)keyboardWillHide:(NSNotification *)aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
self.tableView.contentInset = contentInsets;
self.tableView.scrollIndicatorInsets = contentInsets;
}
Two solutions:
Preferred: use a UITableViewController instead of a UIViewController as that one will automatically make sure that your keypad won't hide the editable field.
Hacky: How to make a UITextField move up when keyboard is present?
I've always used a two fold solution for this.
To do this, I register keyboard show/hide events and act accordingly when they get called.
- (void)keyboardWillShow:(NSNotification *)note {
[self updateForKeyboardShowHide:note appearing:YES];
}
- (void)keyboardWillHide:(NSNotification *)note {
[self updateForKeyboardShowHide:note appearing:NO];
}
- (void)updateForKeyboardShowHide:(NSNotification *)note appearing:(BOOL)isAppearing {
// ignore notifications if our view isn't attached to the window
if (self.view.window == nil)
return;
CGFloat directionalModifier = isAppearing?-1:1;
CGRect keyboardBounds = [[note.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGFloat animationDuration = [[note.userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
// figure out table re-size based on keyboard
CGFloat keyboardHeight;
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (UIInterfaceOrientationIsPortrait(orientation))
keyboardHeight = keyboardBounds.size.height;
else
keyboardHeight = keyboardBounds.size.width;
[UIView animateWithDuration:animationDuration animations:^{
// resize table
CGRect newFrame = table.frame;
newFrame.size.height += [self calculateKeyboardOffsetWithHeight:keyboardHeight] * directionalModifier;
table.frame = newFrame;
} completion:^(BOOL finished){
// scroll to selected cell
if (isAppearing) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:textFieldInEdit.tag inSection:0];
[table scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
}];
}
- (CGFloat)calulateKeyboardOffsetWithHeight:(CGFloat)keyboardHeight {
// This depends on the size and position of your table.
// If your table happen to go all the way to the bottom of
// the screen, you'll needs to adjust it's size by the whole keyboard height.
// You might as well ditch this method and inline the value.
return keyboardHeight;
// My table did not go to the bottom of the screen and the position was
// change dynamically so and there was long boring calculation I needed to
// do to figure out how much my table needed to shrink/grow.
}
When your table view contains data entry fields like a UITextField or a UITextView and the table view is long enough to cover the screen, you will have a problem accessing data entry fields that are hidden by the keyboard.
To overcome this problem two solutions are:
The easiest and recommended way is to use a UITableViewController instead of UIViewController, which automatic make sure keypad won't hide the editable field (If possible use this approach to avoid U.I. adjustment inconvenience)
If you use a UIViewController and a UITableView as its subview. You can scroll your UI’s frame by observing the UIKeyboardWillShowNotification and UIKeyboardWillHideNotification
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification object:nil]; //Posted immediately prior to the display of the keyboard
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification object:nil]; //Posted immediately prior to the dismissal of the keyboard.
}
- (void)keyboardWillShow:(NSNotification *)aNotification
{
CGRect keyboardBounds = [[[aNotification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardBounds.size.height, 0); //when keyboard is up, that time just bring your text filed above the keyboard
self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(0, 0, keyboardBounds.size.height, 0);
[self.tableView scrollToRowAtIndexPath:[self findIndexPathToScroll]
atScrollPosition:UITableViewScrollPositionTop
animated:YES]; //findIndexPathToScroll implementation not shown
[UIView commitAnimations];
}
- (void)keyboardWillHide:(NSNotification *)aNotification
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
self.tableView.contentInset = UIEdgeInsetsZero; //Once keyboard is hidden then bring back your table into your original position.
self.tableView.scrollIndicatorInsets = UIEdgeInsetsZero;
[UIView commitAnimations];
}
registerForKeyboardNotifications - call this method when you load the UITableView, ie: viewDidLoad
findIndexPathToScroll - (Implementation not shown) Its your business logic to prepare IndexPath where table view should scroll
removeObserver 'UIKeyboardWillShowNotification' and 'UIKeyboardWillHideNotification' both in dealloc and viewDidUnloadA simple solution. Implement the heightForFooter method, and let it return a value of (say) 100, and when you select the a cell in UITableView, they will simply slide up by that height, and the keyboard will not cover the view.