Skip to content

Instantly share code, notes, and snippets.

@rcfrias
Created September 25, 2014 04:32
Show Gist options
  • Save rcfrias/78e5d922727a5f897b60 to your computer and use it in GitHub Desktop.
Save rcfrias/78e5d922727a5f897b60 to your computer and use it in GitHub Desktop.
UIViewController TextFields hidden by keyboard. Using this setup, we solve this basic UI issue without the need of UIScrollView. Supports iOS8 new QuickType feature. The example assumes, the ViewController.h header implements UITextFieldDelegate
//
// ViewController.m
//
// Created by Roberto Frias on 22/08/14.
// Copyright (c) 2014 gmri. All rights reserved.
//
#import "ViewController.h"
@implementation ViewController{
@private
UITextField *currentTextField;
BOOL isViewPushed;
int pushedHeight;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Register this view to listen the UIKeyboardWillShowNotification to get keyboard's height.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
// Get a reference to the currentField, so that we can dispose of using outlets.
currentTextField = textField;
}
// Using WillShow notification will let us know the height of the keyboard before it is displayed.
- (void)keyboardWillShow:(NSNotification *)notification
{
const float movementDuration = 0.3f; // Standard duration for iOS
// Get the size of the keyboard.
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
// Get the position of the keyboard. Needed for iOS 8 QuickType fields.
CGPoint keyboardCoords = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].origin;
// Given size may not account for screen rotation
float keyboardHeight = MIN(keyboardSize.height,keyboardSize.width);
// Get the position of current TextField, so we know if it will be hidden by the keyboard
CGPoint p = [currentTextField.superview convertPoint:currentTextField.frame.origin toView:self.view];
// Self explanatory
int screenHeight = [[UIScreen mainScreen] bounds].size.height;
int availableSpace = screenHeight - keyboardHeight;
int fieldHeight = currentTextField.frame.size.height;
int fieldBelowSpace = 10;
int neededSpace = p.y + fieldHeight + fieldBelowSpace;
if (availableSpace < neededSpace) {
int spaceToAdd = availableSpace-neededSpace;
// This fixes collition animation between keyboards with and without QuickType
if (screenHeight != keyboardCoords.y) {
spaceToAdd -= keyboardCoords.y - keyboardHeight;
}
// Flag to remember if we need to reset the view.
isViewPushed = YES;
// Animation to push the view the spaceToAdd
[UIView beginAnimations: @"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, spaceToAdd);
[UIView commitAnimations];
// Class variable accessible on the close function.
pushedHeight = spaceToAdd;
}
}
// Reseting the view container if moved
- (void)textFieldDidEndEditing:(UITextField *)textField
{
if (isViewPushed) {
isViewPushed = NO;
const float movementDuration = 0.3f; // tweak as needed
[UIView beginAnimations: @"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, -pushedHeight);
[UIView commitAnimations];
}
}
// I havent found a way to dismiss the keyboard without knowing the potential responders, so you would have to
// connect the outlets to dismiss the keyboard so that the "textFieldDidBeginEditing" and
// "textFieldDidEndEditing" get called.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
if ([_tiEmailAddress isFirstResponder] && [touch view] != _tiEmailAddress) {
[_tiEmailAddress resignFirstResponder];
}
if ([_tiPassword isFirstResponder] && [touch view] != _tiPassword) {
[_tiPassword resignFirstResponder];
}
[super touchesBegan:touches withEvent:event];
}
-(BOOL) textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment