forked from michaeltyson/TPKeyboardAvoiding
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTPKeyboardAvoidingTableView.m
116 lines (94 loc) · 4.69 KB
/
TPKeyboardAvoidingTableView.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//
// 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;
@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 style:(UITableViewStyle)style {
if ( !(self = [super initWithFrame:frame style:style]) ) return nil;
[self setup];
return self;
}
-(void)awakeFromNib {
[self setup];
}
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (void)keyboardWillShow:(NSNotification*)notification {
if ( !CGRectEqualToRect(priorFrame, CGRectZero) ) return;
UIView *firstResponder = [self findFirstResponderBeneathView:self];
if ( !firstResponder ) {
// No child view is the first responder - nothing to do here
return;
}
priorFrame = self.frame;
// Use this view's coordinate system
CGRect keyboardBounds = [self convertRect:[[[notification userInfo] objectForKey:_UIKeyboardFrameEndUserInfoKey] CGRectValue] fromView:nil];
CGRect screenBounds = [self convertRect:[UIScreen mainScreen].bounds fromView:nil];
if ( keyboardBounds.origin.y == 0 ) keyboardBounds.origin = CGPointMake(0, screenBounds.size.height - keyboardBounds.size.height);
CGFloat spaceAboveKeyboard = keyboardBounds.origin.y - self.bounds.origin.y;
CGFloat offset = -1;
CGRect newFrame = self.frame;
newFrame.size.height -= keyboardBounds.size.height -
((keyboardBounds.origin.y+keyboardBounds.size.height)
- (self.bounds.origin.y+self.bounds.size.height));
CGRect firstResponderFrame = [firstResponder convertRect:firstResponder.bounds toView:self];
if ( firstResponderFrame.origin.y + firstResponderFrame.size.height >= screenBounds.origin.y + screenBounds.size.height - keyboardBounds.size.height ) {
// Prepare to scroll to make sure the view is above the keyboard
offset = firstResponderFrame.origin.y + self.contentOffset.y;
if ( self.contentSize.height - offset < newFrame.size.height ) {
// Scroll to the bottom
offset = self.contentSize.height - newFrame.size.height;
} else {
if ( firstResponder.bounds.size.height < spaceAboveKeyboard ) {
// Center vertically if there's room
offset -= floor((spaceAboveKeyboard-firstResponder.bounds.size.height)/2.0);
}
if ( offset + newFrame.size.height > self.contentSize.height ) {
// Clamp to content size
offset = self.contentSize.height - newFrame.size.height;
}
}
}
// Shrink view's height 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.frame = newFrame;
if ( offset != -1 ) {
[self setContentOffset:CGPointMake(self.contentOffset.x, offset) animated:YES];
}
[UIView commitAnimations];
}
- (void)keyboardWillHide:(NSNotification*)notification {
if ( CGRectEqualToRect(priorFrame, CGRectZero) ) return;
// 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.frame = priorFrame;
priorFrame = CGRectZero;
[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;
}
@end