Created
July 9, 2010 23:22
-
-
Save roman/470236 to your computer and use it in GitHub Desktop.
Delegate that handles all the annoying gotchas of textfields
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// As see on: http://cocoawithlove.com/2008/10/sliding-uitextfields-around-to-avoid.html | |
#import <Foundation/Foundation.h> | |
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; | |
static const CGFloat LANDSCAPE_KEYBOARD_HEIGHT = 162; | |
@interface TextFieldDelegate : NSObject <UITextFieldDelegate> { | |
UIView *view; | |
CGFloat animatedDistance; | |
} | |
@property (retain, nonatomic) UIView *view; | |
- (TextFieldDelegate*) initWithView:(UIView*) _view; | |
@end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// as seen on: http://cocoawithlove.com/2008/10/sliding-uitextfields-around-to-avoid.html | |
#import "TextFieldDelegate.h" | |
@implementation TextFieldDelegate | |
@synthesize view; | |
- (TextFieldDelegate*) initWithView:(UIView*) _view { | |
if (self = [super init]) { | |
self.view = _view; | |
} | |
return self; | |
} | |
- (void) textFieldDidBeginEditing:(UITextField *)textField { | |
// Get the rects of the text field being edited and the view that we're going to scroll. | |
// We convert everything to window coordinates, since they're not necessarily in the same | |
// coordinate space. | |
CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField]; | |
CGRect viewRect = [self.view.window convertRect:self.view.bounds fromView:self.view]; | |
// So now we have the bounds, we need to calculate the fraction between the top and bottom of | |
// the middle section for the text field's midline: | |
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; | |
// Clamp this fraction so that the top section is all "0.0" and the bottom section is all "1.0". | |
if (heightFraction < 0.0) | |
{ | |
heightFraction = 0.0; | |
} | |
else if (heightFraction > 1.0) | |
{ | |
heightFraction = 1.0; | |
} | |
// Now take this fraction and convert it into an amount to scroll by multiplying by the keyboard height | |
// for the current screen orientation. Notice the calls to floor so that we only scroll by whole pixel amounts. | |
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; | |
if (orientation == UIInterfaceOrientationPortrait || | |
orientation == UIInterfaceOrientationPortraitUpsideDown) { | |
animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction); | |
} | |
else { | |
animatedDistance = floor(LANDSCAPE_KEYBOARD_HEIGHT * heightFraction); | |
} | |
// Finally, apply the animation. Note the use of setAnimationBeginsFromCurrentState: | |
// — this will allow a smooth transition to new text field if the user taps on another. | |
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) textFieldDidEndEditing:(UITextField *)textField { | |
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]; | |
} | |
- (BOOL) textFieldShouldReturn:(UITextField *)textField { | |
[textField resignFirstResponder]; | |
return YES; | |
} | |
- (void) dealloc { | |
[self.view release]; | |
[super dealloc]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment