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 viewDidUnload
A 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.