forked from mirrors/linphone-iphone
173 lines
6 KiB
Objective-C
Executable file
173 lines
6 KiB
Objective-C
Executable file
//
|
|
// TPKeyboardAvoidingTableView.m
|
|
//
|
|
// Created by Michael Tyson on 11/04/2011.
|
|
// Copyright 2011 A Tasty Pixel. All rights reserved.
|
|
//
|
|
|
|
#import "TPKeyboardAvoidingTableView.h"
|
|
|
|
#define _UIKeyboardFrameEndUserInfoKey (&UIKeyboardFrameEndUserInfoKey != NULL ? UIKeyboardFrameEndUserInfoKey : @"UIKeyboardBoundsUserInfoKey")
|
|
|
|
@interface TPKeyboardAvoidingTableView ()
|
|
- (UIView*)findFirstResponderBeneathView:(UIView*)view;
|
|
- (UIEdgeInsets)contentInsetForKeyboard;
|
|
- (CGFloat)idealOffsetForView:(UIView *)view withSpace:(CGFloat)space;
|
|
- (CGRect)keyboardRect;
|
|
@end
|
|
|
|
@implementation TPKeyboardAvoidingTableView
|
|
|
|
- (void)setup {
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
|
|
}
|
|
|
|
-(id)initWithFrame:(CGRect)frame {
|
|
if ( !(self = [super initWithFrame:frame]) ) return nil;
|
|
[self setup];
|
|
return self;
|
|
}
|
|
|
|
-(id)initWithCoder:(NSCoder *)aDecoder {
|
|
if ( !(self = [super initWithCoder:aDecoder]) ) return nil;
|
|
[self setup];
|
|
return self;
|
|
}
|
|
|
|
-(void)dealloc {
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
#if !__has_feature(objc_arc)
|
|
[super dealloc];
|
|
#endif
|
|
}
|
|
|
|
-(void)setFrame:(CGRect)frame {
|
|
[super setFrame:frame];
|
|
if ( _keyboardVisible ) {
|
|
self.contentInset = [self contentInsetForKeyboard];
|
|
}
|
|
}
|
|
|
|
-(void)setContentSize:(CGSize)contentSize {
|
|
[super setContentSize:contentSize];
|
|
if ( _keyboardVisible ) {
|
|
self.contentInset = [self contentInsetForKeyboard];
|
|
}
|
|
}
|
|
|
|
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
|
|
[[self findFirstResponderBeneathView:self] resignFirstResponder];
|
|
[super touchesEnded:touches withEvent:event];
|
|
}
|
|
|
|
- (void)keyboardWillShow:(NSNotification*)notification {
|
|
_keyboardRect = [[[notification userInfo] objectForKey:_UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
|
_keyboardVisible = YES;
|
|
|
|
UIView *firstResponder = [self findFirstResponderBeneathView:self];
|
|
if ( !firstResponder ) {
|
|
// No child view is the first responder - nothing to do here
|
|
return;
|
|
}
|
|
|
|
if (!_priorInsetSaved) {
|
|
_priorInset = self.contentInset;
|
|
_priorInsetSaved = YES;
|
|
}
|
|
|
|
// Shrink view's inset by the keyboard's height, and scroll to show the text field/view being edited
|
|
[UIView beginAnimations:nil context:NULL];
|
|
[UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
|
|
[UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]];
|
|
|
|
self.contentInset = [self contentInsetForKeyboard];
|
|
[self setContentOffset:CGPointMake(self.contentOffset.x,
|
|
[self idealOffsetForView:firstResponder withSpace:[self keyboardRect].origin.y - self.bounds.origin.y])
|
|
animated:YES];
|
|
[self setScrollIndicatorInsets:self.contentInset];
|
|
|
|
[UIView commitAnimations];
|
|
}
|
|
|
|
- (void)keyboardWillHide:(NSNotification*)notification {
|
|
_keyboardRect = CGRectZero;
|
|
_keyboardVisible = NO;
|
|
|
|
// Restore dimensions to prior size
|
|
[UIView beginAnimations:nil context:NULL];
|
|
[UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
|
|
[UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]];
|
|
self.contentInset = _priorInset;
|
|
[self setScrollIndicatorInsets:self.contentInset];
|
|
_priorInsetSaved = NO;
|
|
[UIView commitAnimations];
|
|
}
|
|
|
|
- (UIView*)findFirstResponderBeneathView:(UIView*)view {
|
|
// Search recursively for first responder
|
|
for ( UIView *childView in view.subviews ) {
|
|
if ( [childView respondsToSelector:@selector(isFirstResponder)] && [childView isFirstResponder] ) return childView;
|
|
UIView *result = [self findFirstResponderBeneathView:childView];
|
|
if ( result ) return result;
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
- (UIEdgeInsets)contentInsetForKeyboard {
|
|
UIEdgeInsets newInset = self.contentInset;
|
|
CGRect keyboardRect = [self keyboardRect];
|
|
newInset.bottom = keyboardRect.size.height - ((keyboardRect.origin.y+keyboardRect.size.height) - (self.bounds.origin.y+self.bounds.size.height));
|
|
return newInset;
|
|
}
|
|
|
|
-(CGFloat)idealOffsetForView:(UIView *)view withSpace:(CGFloat)space {
|
|
|
|
// Convert the rect to get the view's distance from the top of the scrollView.
|
|
CGRect rect = [view convertRect:view.bounds toView:self];
|
|
|
|
// Set starting offset to that point
|
|
CGFloat offset = rect.origin.y;
|
|
|
|
|
|
if ( self.contentSize.height - offset < space ) {
|
|
// Scroll to the bottom
|
|
offset = self.contentSize.height - space;
|
|
} else {
|
|
if ( view.bounds.size.height < space ) {
|
|
// Center vertically if there's room
|
|
offset -= floor((space-view.bounds.size.height)/2.0);
|
|
}
|
|
if ( offset + space > self.contentSize.height ) {
|
|
// Clamp to content size
|
|
offset = self.contentSize.height - space;
|
|
}
|
|
}
|
|
|
|
if (offset < 0) offset = 0;
|
|
|
|
return offset;
|
|
}
|
|
|
|
-(void)adjustOffsetToIdealIfNeeded {
|
|
|
|
// Only do this if the keyboard is already visible
|
|
if ( !_keyboardVisible ) return;
|
|
|
|
CGFloat visibleSpace = self.bounds.size.height - self.contentInset.top - self.contentInset.bottom;
|
|
|
|
CGPoint idealOffset = CGPointMake(0, [self idealOffsetForView:[self findFirstResponderBeneathView:self] withSpace:visibleSpace]);
|
|
|
|
[self setContentOffset:idealOffset animated:YES];
|
|
}
|
|
|
|
- (CGRect)keyboardRect {
|
|
CGRect keyboardRect = [self convertRect:_keyboardRect fromView:nil];
|
|
if ( keyboardRect.origin.y == 0 ) {
|
|
CGRect screenBounds = [self convertRect:[UIScreen mainScreen].bounds fromView:nil];
|
|
keyboardRect.origin = CGPointMake(0, screenBounds.size.height - keyboardRect.size.height);
|
|
}
|
|
return keyboardRect;
|
|
}
|
|
|
|
@end
|