Commit 7597b958ff8048902c85e111ff941a72265a1432

Authored by phong
1 parent f35b3f9a70

fix bug baseviewcontroller

Showing 16 changed files with 822 additions and 822 deletions Side-by-side Diff

LifeLog/LifeLog/TPKeyboardAvoiding/TPKeyboardAvoidingCollectionView.h
1   -//
2   -// TPKeyboardAvoidingCollectionView.h
3   -// TPKeyboardAvoiding
4   -//
5   -// Created by Michael Tyson on 30/09/2013.
6   -// Copyright 2015 A Tasty Pixel & The CocoaBots. All rights reserved.
7   -//
8   -
9   -#import <UIKit/UIKit.h>
10   -#import "UIScrollView+TPKeyboardAvoidingAdditions.h"
11   -
12   -@interface TPKeyboardAvoidingCollectionView : UICollectionView <UITextFieldDelegate, UITextViewDelegate>
13   -- (BOOL)focusNextTextField;
14   -- (void)scrollToActiveTextField;
15   -@end
LifeLog/LifeLog/TPKeyboardAvoiding/TPKeyboardAvoidingCollectionView.m
1   -//
2   -// TPKeyboardAvoidingCollectionView.m
3   -// TPKeyboardAvoiding
4   -//
5   -// Created by Michael Tyson on 30/09/2013.
6   -// Copyright 2015 A Tasty Pixel & The CocoaBots. All rights reserved.
7   -//
8   -
9   -#import "TPKeyboardAvoidingCollectionView.h"
10   -
11   -@interface TPKeyboardAvoidingCollectionView () <UITextFieldDelegate, UITextViewDelegate>
12   -@end
13   -
14   -@implementation TPKeyboardAvoidingCollectionView
15   -
16   -#pragma mark - Setup/Teardown
17   -
18   -- (void)setup {
19   - if ( [self hasAutomaticKeyboardAvoidingBehaviour] ) return;
20   -
21   - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(TPKeyboardAvoiding_keyboardWillShow:) name:UIKeyboardWillChangeFrameNotification object:nil];
22   - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(TPKeyboardAvoiding_keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
23   - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollToActiveTextField) name:UITextViewTextDidBeginEditingNotification object:nil];
24   - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollToActiveTextField) name:UITextFieldTextDidBeginEditingNotification object:nil];
25   -}
26   -
27   --(id)initWithFrame:(CGRect)frame {
28   - if ( !(self = [super initWithFrame:frame]) ) return nil;
29   - [self setup];
30   - return self;
31   -}
32   -
33   -- (id)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout {
34   - if ( !(self = [super initWithFrame:frame collectionViewLayout:layout]) ) return nil;
35   - [self setup];
36   - return self;
37   -}
38   -
39   --(void)awakeFromNib {
40   - [super awakeFromNib];
41   - [self setup];
42   -}
43   -
44   --(void)dealloc {
45   - [[NSNotificationCenter defaultCenter] removeObserver:self];
46   -#if !__has_feature(objc_arc)
47   - [super dealloc];
48   -#endif
49   -}
50   -
51   -
52   --(BOOL)hasAutomaticKeyboardAvoidingBehaviour {
53   - if ( [[[UIDevice currentDevice] systemVersion] integerValue] >= 9
54   - && [self.delegate isKindOfClass:[UICollectionViewController class]] ) {
55   - // Theory: It looks like iOS 9's collection views automatically avoid the keyboard. As usual
56   - // Apple have totally failed to document this anywhere, so this is just a guess.
57   - return YES;
58   - }
59   -
60   - return NO;
61   -}
62   -
63   --(void)setFrame:(CGRect)frame {
64   - [super setFrame:frame];
65   - [self TPKeyboardAvoiding_updateContentInset];
66   -}
67   -
68   --(void)setContentSize:(CGSize)contentSize {
69   - if (CGSizeEqualToSize(contentSize, self.contentSize)) {
70   - // Prevent triggering contentSize when it's already the same that
71   - // cause weird infinte scrolling and locking bug
72   - return;
73   - }
74   - [super setContentSize:contentSize];
75   - [self TPKeyboardAvoiding_updateContentInset];
76   -}
77   -
78   -- (BOOL)focusNextTextField {
79   - return [self TPKeyboardAvoiding_focusNextTextField];
80   -
81   -}
82   -- (void)scrollToActiveTextField {
83   - return [self TPKeyboardAvoiding_scrollToActiveTextField];
84   -}
85   -
86   -#pragma mark - Responders, events
87   -
88   --(void)willMoveToSuperview:(UIView *)newSuperview {
89   - [super willMoveToSuperview:newSuperview];
90   - if ( !newSuperview ) {
91   - [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) object:self];
92   - }
93   -}
94   -
95   -- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
96   - [[self TPKeyboardAvoiding_findFirstResponderBeneathView:self] resignFirstResponder];
97   - [super touchesEnded:touches withEvent:event];
98   -}
99   -
100   --(BOOL)textFieldShouldReturn:(UITextField *)textField {
101   - if ( ![self focusNextTextField] ) {
102   - [textField resignFirstResponder];
103   - }
104   - return YES;
105   -}
106   -
107   --(void)layoutSubviews {
108   - [super layoutSubviews];
109   - [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) object:self];
110   - [self performSelector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) withObject:self afterDelay:0.1];
111   -}
112   -
113   -@end
LifeLog/LifeLog/TPKeyboardAvoiding/TPKeyboardAvoidingScrollView.h
1   -//
2   -// TPKeyboardAvoidingScrollView.h
3   -// TPKeyboardAvoiding
4   -//
5   -// Created by Michael Tyson on 30/09/2013.
6   -// Copyright 2015 A Tasty Pixel. All rights reserved.
7   -//
8   -
9   -#import <UIKit/UIKit.h>
10   -#import "UIScrollView+TPKeyboardAvoidingAdditions.h"
11   -
12   -@interface TPKeyboardAvoidingScrollView : UIScrollView <UITextFieldDelegate, UITextViewDelegate>
13   -- (void)contentSizeToFit;
14   -- (BOOL)focusNextTextField;
15   -- (void)scrollToActiveTextField;
16   -@end
LifeLog/LifeLog/TPKeyboardAvoiding/TPKeyboardAvoidingScrollView.m
1   -//
2   -// TPKeyboardAvoidingScrollView.m
3   -// TPKeyboardAvoiding
4   -//
5   -// Created by Michael Tyson on 30/09/2013.
6   -// Copyright 2015 A Tasty Pixel. All rights reserved.
7   -//
8   -
9   -#import "TPKeyboardAvoidingScrollView.h"
10   -
11   -@interface TPKeyboardAvoidingScrollView () <UITextFieldDelegate, UITextViewDelegate>
12   -@end
13   -
14   -@implementation TPKeyboardAvoidingScrollView
15   -
16   -#pragma mark - Setup/Teardown
17   -
18   -- (void)setup {
19   - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(TPKeyboardAvoiding_keyboardWillShow:) name:UIKeyboardWillChangeFrameNotification object:nil];
20   - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(TPKeyboardAvoiding_keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
21   - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollToActiveTextField) name:UITextViewTextDidBeginEditingNotification object:nil];
22   - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollToActiveTextField) name:UITextFieldTextDidBeginEditingNotification object:nil];
23   -}
24   -
25   --(id)initWithFrame:(CGRect)frame {
26   - if ( !(self = [super initWithFrame:frame]) ) return nil;
27   - [self setup];
28   - return self;
29   -}
30   -
31   --(void)awakeFromNib {
32   - [super awakeFromNib];
33   - [self setup];
34   -}
35   -
36   --(void)dealloc {
37   - [[NSNotificationCenter defaultCenter] removeObserver:self];
38   -#if !__has_feature(objc_arc)
39   - [super dealloc];
40   -#endif
41   -}
42   -
43   --(void)setFrame:(CGRect)frame {
44   - [super setFrame:frame];
45   - [self TPKeyboardAvoiding_updateContentInset];
46   -}
47   -
48   --(void)setContentSize:(CGSize)contentSize {
49   - [super setContentSize:contentSize];
50   - [self TPKeyboardAvoiding_updateFromContentSizeChange];
51   -}
52   -
53   -- (void)contentSizeToFit {
54   - self.contentSize = [self TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames];
55   -}
56   -
57   -- (BOOL)focusNextTextField {
58   - return [self TPKeyboardAvoiding_focusNextTextField];
59   -
60   -}
61   -- (void)scrollToActiveTextField {
62   - return [self TPKeyboardAvoiding_scrollToActiveTextField];
63   -}
64   -
65   -#pragma mark - Responders, events
66   -
67   --(void)willMoveToSuperview:(UIView *)newSuperview {
68   - [super willMoveToSuperview:newSuperview];
69   - if ( !newSuperview ) {
70   - [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) object:self];
71   - }
72   -}
73   -
74   -- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
75   - [[self TPKeyboardAvoiding_findFirstResponderBeneathView:self] resignFirstResponder];
76   - [super touchesEnded:touches withEvent:event];
77   -}
78   -
79   --(BOOL)textFieldShouldReturn:(UITextField *)textField {
80   - if ( ![self focusNextTextField] ) {
81   - [textField resignFirstResponder];
82   - }
83   - return YES;
84   -}
85   -
86   --(void)layoutSubviews {
87   - [super layoutSubviews];
88   - [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) object:self];
89   - [self performSelector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) withObject:self afterDelay:0.1];
90   -}
91   -
92   -@end
LifeLog/LifeLog/TPKeyboardAvoiding/TPKeyboardAvoidingTableView.h
1   -//
2   -// TPKeyboardAvoidingTableView.h
3   -// TPKeyboardAvoiding
4   -//
5   -// Created by Michael Tyson on 30/09/2013.
6   -// Copyright 2015 A Tasty Pixel. All rights reserved.
7   -//
8   -
9   -#import <UIKit/UIKit.h>
10   -#import "UIScrollView+TPKeyboardAvoidingAdditions.h"
11   -
12   -@interface TPKeyboardAvoidingTableView : UITableView <UITextFieldDelegate, UITextViewDelegate>
13   -- (BOOL)focusNextTextField;
14   -- (void)scrollToActiveTextField;
15   -@end
LifeLog/LifeLog/TPKeyboardAvoiding/TPKeyboardAvoidingTableView.m
1   -//
2   -// TPKeyboardAvoidingTableView.m
3   -// TPKeyboardAvoiding
4   -//
5   -// Created by Michael Tyson on 30/09/2013.
6   -// Copyright 2015 A Tasty Pixel. All rights reserved.
7   -//
8   -
9   -#import "TPKeyboardAvoidingTableView.h"
10   -
11   -@interface TPKeyboardAvoidingTableView () <UITextFieldDelegate, UITextViewDelegate>
12   -@end
13   -
14   -@implementation TPKeyboardAvoidingTableView
15   -
16   -#pragma mark - Setup/Teardown
17   -
18   -- (void)setup {
19   - if ( [self hasAutomaticKeyboardAvoidingBehaviour] ) return;
20   -
21   - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(TPKeyboardAvoiding_keyboardWillShow:) name:UIKeyboardWillChangeFrameNotification object:nil];
22   - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(TPKeyboardAvoiding_keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
23   - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollToActiveTextField) name:UITextViewTextDidBeginEditingNotification object:nil];
24   - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollToActiveTextField) name:UITextFieldTextDidBeginEditingNotification object:nil];
25   -}
26   -
27   --(id)initWithFrame:(CGRect)frame {
28   - if ( !(self = [super initWithFrame:frame]) ) return nil;
29   - [self setup];
30   - return self;
31   -}
32   -
33   --(id)initWithFrame:(CGRect)frame style:(UITableViewStyle)withStyle {
34   - if ( !(self = [super initWithFrame:frame style:withStyle]) ) return nil;
35   - [self setup];
36   - return self;
37   -}
38   -
39   --(void)awakeFromNib {
40   - [super awakeFromNib];
41   - [self setup];
42   -}
43   -
44   --(void)dealloc {
45   - [[NSNotificationCenter defaultCenter] removeObserver:self];
46   -#if !__has_feature(objc_arc)
47   - [super dealloc];
48   -#endif
49   -}
50   -
51   --(BOOL)hasAutomaticKeyboardAvoidingBehaviour {
52   - if ( [self.delegate isKindOfClass:[UITableViewController class]] ) {
53   - // Theory: Apps built using the iOS 8.3 SDK (probably: older SDKs not tested) seem to handle keyboard
54   - // avoiding automatically with UITableViewController. This doesn't seem to be documented anywhere
55   - // by Apple, so results obtained only empirically.
56   - return YES;
57   - }
58   -
59   - return NO;
60   -}
61   -
62   --(void)setFrame:(CGRect)frame {
63   - [super setFrame:frame];
64   - if ( [self hasAutomaticKeyboardAvoidingBehaviour] ) return;
65   - [self TPKeyboardAvoiding_updateContentInset];
66   -}
67   -
68   --(void)setContentSize:(CGSize)contentSize {
69   - if ( [self hasAutomaticKeyboardAvoidingBehaviour] ) {
70   - [super setContentSize:contentSize];
71   - return;
72   - }
73   - if (CGSizeEqualToSize(contentSize, self.contentSize)) {
74   - // Prevent triggering contentSize when it's already the same
75   - // this cause table view to scroll to top on contentInset changes
76   - return;
77   - }
78   - [super setContentSize:contentSize];
79   - [self TPKeyboardAvoiding_updateContentInset];
80   -}
81   -
82   -- (BOOL)focusNextTextField {
83   - return [self TPKeyboardAvoiding_focusNextTextField];
84   -
85   -}
86   -- (void)scrollToActiveTextField {
87   - return [self TPKeyboardAvoiding_scrollToActiveTextField];
88   -}
89   -
90   -#pragma mark - Responders, events
91   -
92   --(void)willMoveToSuperview:(UIView *)newSuperview {
93   - [super willMoveToSuperview:newSuperview];
94   - if ( !newSuperview ) {
95   - [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) object:self];
96   - }
97   -}
98   -
99   -- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
100   - [[self TPKeyboardAvoiding_findFirstResponderBeneathView:self] resignFirstResponder];
101   - [super touchesEnded:touches withEvent:event];
102   -}
103   -
104   --(BOOL)textFieldShouldReturn:(UITextField *)textField {
105   - if ( ![self focusNextTextField] ) {
106   - [textField resignFirstResponder];
107   - }
108   - return YES;
109   -}
110   -
111   --(void)layoutSubviews {
112   - [super layoutSubviews];
113   - [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) object:self];
114   - [self performSelector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) withObject:self afterDelay:0.1];
115   -}
116   -
117   -@end
LifeLog/LifeLog/TPKeyboardAvoiding/UIScrollView+TPKeyboardAvoidingAdditions.h
1   -//
2   -// UIScrollView+TPKeyboardAvoidingAdditions.h
3   -// TPKeyboardAvoiding
4   -//
5   -// Created by Michael Tyson on 30/09/2013.
6   -// Copyright 2015 A Tasty Pixel. All rights reserved.
7   -//
8   -
9   -#import <UIKit/UIKit.h>
10   -
11   -@interface UIScrollView (TPKeyboardAvoidingAdditions)
12   -- (BOOL)TPKeyboardAvoiding_focusNextTextField;
13   -- (void)TPKeyboardAvoiding_scrollToActiveTextField;
14   -
15   -- (void)TPKeyboardAvoiding_keyboardWillShow:(NSNotification*)notification;
16   -- (void)TPKeyboardAvoiding_keyboardWillHide:(NSNotification*)notification;
17   -- (void)TPKeyboardAvoiding_updateContentInset;
18   -- (void)TPKeyboardAvoiding_updateFromContentSizeChange;
19   -- (void)TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:(UIView*)view;
20   -- (UIView*)TPKeyboardAvoiding_findFirstResponderBeneathView:(UIView*)view;
21   --(CGSize)TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames;
22   -@end
LifeLog/LifeLog/TPKeyboardAvoiding/UIScrollView+TPKeyboardAvoidingAdditions.m
1   -//
2   -// UIScrollView+TPKeyboardAvoidingAdditions.m
3   -// TPKeyboardAvoiding
4   -//
5   -// Created by Michael Tyson on 30/09/2013.
6   -// Copyright 2015 A Tasty Pixel. All rights reserved.
7   -//
8   -
9   -#import "UIScrollView+TPKeyboardAvoidingAdditions.h"
10   -#import "TPKeyboardAvoidingScrollView.h"
11   -#import <objc/runtime.h>
12   -
13   -static const CGFloat kCalculatedContentPadding = 10;
14   -static const CGFloat kMinimumScrollOffsetPadding = 20;
15   -
16   -static NSString * const kUIKeyboardAnimationDurationUserInfoKey = @"UIKeyboardAnimationDurationUserInfoKey";
17   -
18   -static const int kStateKey;
19   -
20   -#define _UIKeyboardFrameEndUserInfoKey (&UIKeyboardFrameEndUserInfoKey != NULL ? UIKeyboardFrameEndUserInfoKey : @"UIKeyboardBoundsUserInfoKey")
21   -
22   -@interface TPKeyboardAvoidingState : NSObject
23   -@property (nonatomic, assign) UIEdgeInsets priorInset;
24   -@property (nonatomic, assign) UIEdgeInsets priorScrollIndicatorInsets;
25   -@property (nonatomic, assign) BOOL keyboardVisible;
26   -@property (nonatomic, assign) CGRect keyboardRect;
27   -@property (nonatomic, assign) CGSize priorContentSize;
28   -@property (nonatomic, assign) BOOL priorPagingEnabled;
29   -@property (nonatomic, assign) BOOL ignoringNotifications;
30   -@property (nonatomic, assign) BOOL keyboardAnimationInProgress;
31   -@property (nonatomic, assign) CGFloat animationDuration;
32   -@end
33   -
34   -@implementation UIScrollView (TPKeyboardAvoidingAdditions)
35   -
36   -- (TPKeyboardAvoidingState*)keyboardAvoidingState {
37   - TPKeyboardAvoidingState *state = objc_getAssociatedObject(self, &kStateKey);
38   - if ( !state ) {
39   - state = [[TPKeyboardAvoidingState alloc] init];
40   - objc_setAssociatedObject(self, &kStateKey, state, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
41   -#if !__has_feature(objc_arc)
42   - [state release];
43   -#endif
44   - }
45   - return state;
46   -}
47   -
48   -- (void)TPKeyboardAvoiding_keyboardWillShow:(NSNotification*)notification {
49   - NSDictionary *info = [notification userInfo];
50   - TPKeyboardAvoidingState *state = self.keyboardAvoidingState;
51   -
52   - state.animationDuration = [[info objectForKey:kUIKeyboardAnimationDurationUserInfoKey] doubleValue];
53   -
54   - CGRect keyboardRect = [self convertRect:[[info objectForKey:_UIKeyboardFrameEndUserInfoKey] CGRectValue] fromView:nil];
55   - if (CGRectIsEmpty(keyboardRect)) {
56   - return;
57   - }
58   -
59   - if ( state.ignoringNotifications ) {
60   - return;
61   - }
62   -
63   - state.keyboardRect = keyboardRect;
64   -
65   - if ( !state.keyboardVisible ) {
66   - state.priorInset = self.contentInset;
67   - state.priorScrollIndicatorInsets = self.scrollIndicatorInsets;
68   - state.priorPagingEnabled = self.pagingEnabled;
69   - }
70   -
71   - state.keyboardVisible = YES;
72   - self.pagingEnabled = NO;
73   -
74   - if ( [self isKindOfClass:[TPKeyboardAvoidingScrollView class]] ) {
75   - state.priorContentSize = self.contentSize;
76   -
77   - if ( CGSizeEqualToSize(self.contentSize, CGSizeZero) ) {
78   - // Set the content size, if it's not set. Do not set content size explicitly if auto-layout
79   - // is being used to manage subviews
80   - self.contentSize = [self TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames];
81   - }
82   - }
83   -
84   - // Delay until a future run loop such that the cursor position is available in a text view
85   - // In other words, it's not available (specifically, the prior cursor position is returned) when the first keyboard position change notification fires
86   - // NOTE: Unfortunately, using dispatch_async(main_queue) did not result in a sufficient-enough delay
87   - // for the text view's current cursor position to be available
88   - dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC));
89   - dispatch_after(delay, dispatch_get_main_queue(), ^{
90   -
91   - // Shrink view's inset by the keyboard's height, and scroll to show the text field/view being edited
92   - [UIView beginAnimations:nil context:NULL];
93   -
94   - [UIView setAnimationDelegate:self];
95   - [UIView setAnimationWillStartSelector:@selector(keyboardViewAppear:context:)];
96   - [UIView setAnimationDidStopSelector:@selector(keyboardViewDisappear:finished:context:)];
97   -
98   - [UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
99   - [UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]];
100   -
101   - UIView *firstResponder = [self TPKeyboardAvoiding_findFirstResponderBeneathView:self];
102   - if ( firstResponder ) {
103   -
104   - self.contentInset = [self TPKeyboardAvoiding_contentInsetForKeyboard];
105   -
106   - CGFloat viewableHeight = self.bounds.size.height - self.contentInset.top - self.contentInset.bottom;
107   - [self setContentOffset:CGPointMake(self.contentOffset.x,
108   - [self TPKeyboardAvoiding_idealOffsetForView:firstResponder
109   - withViewingAreaHeight:viewableHeight])
110   - animated:NO];
111   - }
112   -
113   - self.scrollIndicatorInsets = self.contentInset;
114   - [self layoutIfNeeded];
115   -
116   - [UIView commitAnimations];
117   - });
118   -}
119   -
120   -- (void)keyboardViewAppear:(NSString *)animationID context:(void *)context {
121   - self.keyboardAvoidingState.keyboardAnimationInProgress = true;
122   -}
123   -
124   -- (void)keyboardViewDisappear:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
125   - if (finished.boolValue) {
126   - self.keyboardAvoidingState.keyboardAnimationInProgress = false;
127   - }
128   -}
129   -
130   -- (void)TPKeyboardAvoiding_keyboardWillHide:(NSNotification*)notification {
131   - CGRect keyboardRect = [self convertRect:[[[notification userInfo] objectForKey:_UIKeyboardFrameEndUserInfoKey] CGRectValue] fromView:nil];
132   - if (CGRectIsEmpty(keyboardRect) && !self.keyboardAvoidingState.keyboardAnimationInProgress) {
133   - return;
134   - }
135   -
136   - TPKeyboardAvoidingState *state = self.keyboardAvoidingState;
137   -
138   - if ( state.ignoringNotifications ) {
139   - return;
140   - }
141   -
142   - if ( !state.keyboardVisible ) {
143   - return;
144   - }
145   -
146   - state.keyboardRect = CGRectZero;
147   - state.keyboardVisible = NO;
148   -
149   - // Restore dimensions to prior size
150   - [UIView beginAnimations:nil context:NULL];
151   - [UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
152   - [UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]];
153   -
154   - if ( [self isKindOfClass:[TPKeyboardAvoidingScrollView class]] ) {
155   - self.contentSize = state.priorContentSize;
156   - }
157   -
158   - self.contentInset = state.priorInset;
159   - self.scrollIndicatorInsets = state.priorScrollIndicatorInsets;
160   - self.pagingEnabled = state.priorPagingEnabled;
161   - [self layoutIfNeeded];
162   - [UIView commitAnimations];
163   -}
164   -
165   -- (void)TPKeyboardAvoiding_updateContentInset {
166   - TPKeyboardAvoidingState *state = self.keyboardAvoidingState;
167   - if ( state.keyboardVisible ) {
168   - self.contentInset = [self TPKeyboardAvoiding_contentInsetForKeyboard];
169   - }
170   -}
171   -
172   -- (void)TPKeyboardAvoiding_updateFromContentSizeChange {
173   - TPKeyboardAvoidingState *state = self.keyboardAvoidingState;
174   - if ( state.keyboardVisible ) {
175   - state.priorContentSize = self.contentSize;
176   - self.contentInset = [self TPKeyboardAvoiding_contentInsetForKeyboard];
177   - }
178   -}
179   -
180   -#pragma mark - Utilities
181   -
182   -- (BOOL)TPKeyboardAvoiding_focusNextTextField {
183   - UIView *firstResponder = [self TPKeyboardAvoiding_findFirstResponderBeneathView:self];
184   - if ( !firstResponder ) {
185   - return NO;
186   - }
187   -
188   - UIView *view = [self TPKeyboardAvoiding_findNextInputViewAfterView:firstResponder beneathView:self];
189   -
190   - if ( view ) {
191   - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0), dispatch_get_main_queue(), ^{
192   - TPKeyboardAvoidingState *state = self.keyboardAvoidingState;
193   - state.ignoringNotifications = YES;
194   - [view becomeFirstResponder];
195   - state.ignoringNotifications = NO;
196   - });
197   - return YES;
198   - }
199   -
200   - return NO;
201   -}
202   -
203   --(void)TPKeyboardAvoiding_scrollToActiveTextField {
204   - TPKeyboardAvoidingState *state = self.keyboardAvoidingState;
205   -
206   - if ( !state.keyboardVisible ) return;
207   -
208   - UIView *firstResponder = [self TPKeyboardAvoiding_findFirstResponderBeneathView:self];
209   - if ( !firstResponder ) {
210   - return;
211   - }
212   - // Ignore any keyboard notification that occur while we scroll
213   - // (seems to be an iOS 9 bug that causes jumping text in UITextField)
214   - state.ignoringNotifications = YES;
215   -
216   - CGFloat visibleSpace = self.bounds.size.height - self.contentInset.top - self.contentInset.bottom;
217   -
218   - CGPoint idealOffset
219   - = CGPointMake(self.contentOffset.x,
220   - [self TPKeyboardAvoiding_idealOffsetForView:firstResponder
221   - withViewingAreaHeight:visibleSpace]);
222   -
223   - // Ordinarily we'd use -setContentOffset:animated:YES here, but it interferes with UIScrollView
224   - // behavior which automatically ensures that the first responder is within its bounds
225   - [UIView animateWithDuration:state.animationDuration animations:^{
226   - self.contentOffset = idealOffset;
227   - } completion:^(BOOL finished) {
228   - state.ignoringNotifications = NO;
229   - }];
230   -}
231   -
232   -#pragma mark - Helpers
233   -
234   -- (UIView*)TPKeyboardAvoiding_findFirstResponderBeneathView:(UIView*)view {
235   - // Search recursively for first responder
236   - for ( UIView *childView in view.subviews ) {
237   - if ( [childView respondsToSelector:@selector(isFirstResponder)] && [childView isFirstResponder] ) return childView;
238   - UIView *result = [self TPKeyboardAvoiding_findFirstResponderBeneathView:childView];
239   - if ( result ) return result;
240   - }
241   - return nil;
242   -}
243   -
244   -- (UIView*)TPKeyboardAvoiding_findNextInputViewAfterView:(UIView*)priorView beneathView:(UIView*)view {
245   - UIView * candidate = nil;
246   - [self TPKeyboardAvoiding_findNextInputViewAfterView:priorView beneathView:view bestCandidate:&candidate];
247   - return candidate;
248   -}
249   -
250   -- (void)TPKeyboardAvoiding_findNextInputViewAfterView:(UIView*)priorView beneathView:(UIView*)view bestCandidate:(UIView**)bestCandidate {
251   - // Search recursively for input view below/to right of priorTextField
252   - CGRect priorFrame = [self convertRect:priorView.frame fromView:priorView.superview];
253   - CGRect candidateFrame = *bestCandidate ? [self convertRect:(*bestCandidate).frame fromView:(*bestCandidate).superview] : CGRectZero;
254   - CGFloat bestCandidateHeuristic = [self TPKeyboardAvoiding_nextInputViewHeuristicForViewFrame:candidateFrame];
255   -
256   - for ( UIView *childView in view.subviews ) {
257   - if ( [self TPKeyboardAvoiding_viewIsValidKeyViewCandidate:childView] ) {
258   - CGRect frame = [self convertRect:childView.frame fromView:view];
259   -
260   - // Use a heuristic to evaluate candidates
261   - CGFloat heuristic = [self TPKeyboardAvoiding_nextInputViewHeuristicForViewFrame:frame];
262   -
263   - // Find views beneath, or to the right. For those views that match, choose the view closest to the top left
264   - if ( childView != priorView
265   - && ((fabs(CGRectGetMinY(frame) - CGRectGetMinY(priorFrame)) < FLT_EPSILON && CGRectGetMinX(frame) > CGRectGetMinX(priorFrame))
266   - || CGRectGetMinY(frame) > CGRectGetMinY(priorFrame))
267   - && (!*bestCandidate || heuristic > bestCandidateHeuristic) ) {
268   -
269   - *bestCandidate = childView;
270   - bestCandidateHeuristic = heuristic;
271   - }
272   - } else {
273   - [self TPKeyboardAvoiding_findNextInputViewAfterView:priorView beneathView:childView bestCandidate:bestCandidate];
274   - }
275   - }
276   -}
277   -
278   -- (CGFloat)TPKeyboardAvoiding_nextInputViewHeuristicForViewFrame:(CGRect)frame {
279   - return (-frame.origin.y * 1000.0) // Prefer elements closest to top (most important)
280   - + (-frame.origin.x); // Prefer elements closest to left
281   -}
282   -
283   -- (BOOL)TPKeyboardAvoiding_viewHiddenOrUserInteractionNotEnabled:(UIView *)view {
284   - while ( view ) {
285   - if ( view.hidden || !view.userInteractionEnabled ) {
286   - return YES;
287   - }
288   - view = view.superview;
289   - }
290   - return NO;
291   -}
292   -
293   -- (BOOL)TPKeyboardAvoiding_viewIsValidKeyViewCandidate:(UIView *)view {
294   - if ( [self TPKeyboardAvoiding_viewHiddenOrUserInteractionNotEnabled:view] ) return NO;
295   -
296   - if ( [view isKindOfClass:[UITextField class]] && ((UITextField*)view).enabled ) {
297   - return YES;
298   - }
299   -
300   - if ( [view isKindOfClass:[UITextView class]] && ((UITextView*)view).isEditable ) {
301   - return YES;
302   - }
303   -
304   - return NO;
305   -}
306   -
307   -- (void)TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:(UIView*)view {
308   - for ( UIView *childView in view.subviews ) {
309   - if ( ([childView isKindOfClass:[UITextField class]] || [childView isKindOfClass:[UITextView class]]) ) {
310   - [self TPKeyboardAvoiding_initializeView:childView];
311   - } else {
312   - [self TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:childView];
313   - }
314   - }
315   -}
316   -
317   --(CGSize)TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames {
318   -
319   - BOOL wasShowingVerticalScrollIndicator = self.showsVerticalScrollIndicator;
320   - BOOL wasShowingHorizontalScrollIndicator = self.showsHorizontalScrollIndicator;
321   -
322   - self.showsVerticalScrollIndicator = NO;
323   - self.showsHorizontalScrollIndicator = NO;
324   -
325   - CGRect rect = CGRectZero;
326   - for ( UIView *view in self.subviews ) {
327   - rect = CGRectUnion(rect, view.frame);
328   - }
329   - rect.size.height += kCalculatedContentPadding;
330   -
331   - self.showsVerticalScrollIndicator = wasShowingVerticalScrollIndicator;
332   - self.showsHorizontalScrollIndicator = wasShowingHorizontalScrollIndicator;
333   -
334   - return rect.size;
335   -}
336   -
337   -
338   -- (UIEdgeInsets)TPKeyboardAvoiding_contentInsetForKeyboard {
339   - TPKeyboardAvoidingState *state = self.keyboardAvoidingState;
340   - UIEdgeInsets newInset = self.contentInset;
341   - CGRect keyboardRect = state.keyboardRect;
342   - newInset.bottom = keyboardRect.size.height - MAX((CGRectGetMaxY(keyboardRect) - CGRectGetMaxY(self.bounds)), 0);
343   - return newInset;
344   -}
345   -
346   --(CGFloat)TPKeyboardAvoiding_idealOffsetForView:(UIView *)view withViewingAreaHeight:(CGFloat)viewAreaHeight {
347   - CGSize contentSize = self.contentSize;
348   - __block CGFloat offset = 0.0;
349   -
350   - CGRect subviewRect = [view convertRect:view.bounds toView:self];
351   -
352   - __block CGFloat padding = 0.0;
353   -
354   - void(^centerViewInViewableArea)() = ^ {
355   - // Attempt to center the subview in the visible space
356   - padding = (viewAreaHeight - subviewRect.size.height) / 2;
357   -
358   - // But if that means there will be less than kMinimumScrollOffsetPadding
359   - // pixels above the view, then substitute kMinimumScrollOffsetPadding
360   - if (padding < kMinimumScrollOffsetPadding ) {
361   - padding = kMinimumScrollOffsetPadding;
362   - }
363   -
364   - // Ideal offset places the subview rectangle origin "padding" points from the top of the scrollview.
365   - // If there is a top contentInset, also compensate for this so that subviewRect will not be placed under
366   - // things like navigation bars.
367   - offset = subviewRect.origin.y - padding - self.contentInset.top;
368   - };
369   -
370   - // If possible, center the caret in the visible space. Otherwise, center the entire view in the visible space.
371   - if ([view conformsToProtocol:@protocol(UITextInput)]) {
372   - UIView <UITextInput> *textInput = (UIView <UITextInput>*)view;
373   - UITextPosition *caretPosition = [textInput selectedTextRange].start;
374   - if (caretPosition) {
375   - CGRect caretRect = [self convertRect:[textInput caretRectForPosition:caretPosition] fromView:textInput];
376   -
377   - // Attempt to center the cursor in the visible space
378   - // pixels above the view, then substitute kMinimumScrollOffsetPadding
379   - padding = (viewAreaHeight - caretRect.size.height) / 2;
380   -
381   - // But if that means there will be less than kMinimumScrollOffsetPadding
382   - // pixels above the view, then substitute kMinimumScrollOffsetPadding
383   - if (padding < kMinimumScrollOffsetPadding ) {
384   - padding = kMinimumScrollOffsetPadding;
385   - }
386   -
387   - // Ideal offset places the subview rectangle origin "padding" points from the top of the scrollview.
388   - // If there is a top contentInset, also compensate for this so that subviewRect will not be placed under
389   - // things like navigation bars.
390   - offset = caretRect.origin.y - padding - self.contentInset.top;
391   - } else {
392   - centerViewInViewableArea();
393   - }
394   - } else {
395   - centerViewInViewableArea();
396   - }
397   -
398   - // Constrain the new contentOffset so we can't scroll past the bottom. Note that we don't take the bottom
399   - // inset into account, as this is manipulated to make space for the keyboard.
400   - CGFloat maxOffset = contentSize.height - viewAreaHeight - self.contentInset.top;
401   - if (offset > maxOffset) {
402   - offset = maxOffset;
403   - }
404   -
405   - // Constrain the new contentOffset so we can't scroll past the top, taking contentInsets into account
406   - if ( offset < -self.contentInset.top ) {
407   - offset = -self.contentInset.top;
408   - }
409   -
410   - return offset;
411   -}
412   -
413   -- (void)TPKeyboardAvoiding_initializeView:(UIView*)view {
414   - if ( [view isKindOfClass:[UITextField class]]
415   - && ((UITextField*)view).returnKeyType == UIReturnKeyDefault
416   - && (![(UITextField*)view delegate] || [(UITextField*)view delegate] == (id<UITextFieldDelegate>)self) ) {
417   - [(UITextField*)view setDelegate:(id<UITextFieldDelegate>)self];
418   - UIView *otherView = [self TPKeyboardAvoiding_findNextInputViewAfterView:view beneathView:self];
419   -
420   - if ( otherView ) {
421   - ((UITextField*)view).returnKeyType = UIReturnKeyNext;
422   - } else {
423   - ((UITextField*)view).returnKeyType = UIReturnKeyDone;
424   - }
425   - }
426   -}
427   -
428   -@end
429   -
430   -
431   -@implementation TPKeyboardAvoidingState
432   -@end
LifeLog/LifeLog/TPKeyboardAvoidingCollectionView.h
  1 +//
  2 +// TPKeyboardAvoidingCollectionView.h
  3 +// TPKeyboardAvoiding
  4 +//
  5 +// Created by Michael Tyson on 30/09/2013.
  6 +// Copyright 2015 A Tasty Pixel & The CocoaBots. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +#import "UIScrollView+TPKeyboardAvoidingAdditions.h"
  11 +
  12 +@interface TPKeyboardAvoidingCollectionView : UICollectionView <UITextFieldDelegate, UITextViewDelegate>
  13 +- (BOOL)focusNextTextField;
  14 +- (void)scrollToActiveTextField;
  15 +@end
LifeLog/LifeLog/TPKeyboardAvoidingCollectionView.m
  1 +//
  2 +// TPKeyboardAvoidingCollectionView.m
  3 +// TPKeyboardAvoiding
  4 +//
  5 +// Created by Michael Tyson on 30/09/2013.
  6 +// Copyright 2015 A Tasty Pixel & The CocoaBots. All rights reserved.
  7 +//
  8 +
  9 +#import "TPKeyboardAvoidingCollectionView.h"
  10 +
  11 +@interface TPKeyboardAvoidingCollectionView () <UITextFieldDelegate, UITextViewDelegate>
  12 +@end
  13 +
  14 +@implementation TPKeyboardAvoidingCollectionView
  15 +
  16 +#pragma mark - Setup/Teardown
  17 +
  18 +- (void)setup {
  19 + if ( [self hasAutomaticKeyboardAvoidingBehaviour] ) return;
  20 +
  21 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(TPKeyboardAvoiding_keyboardWillShow:) name:UIKeyboardWillChangeFrameNotification object:nil];
  22 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(TPKeyboardAvoiding_keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
  23 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollToActiveTextField) name:UITextViewTextDidBeginEditingNotification object:nil];
  24 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollToActiveTextField) name:UITextFieldTextDidBeginEditingNotification object:nil];
  25 +}
  26 +
  27 +-(id)initWithFrame:(CGRect)frame {
  28 + if ( !(self = [super initWithFrame:frame]) ) return nil;
  29 + [self setup];
  30 + return self;
  31 +}
  32 +
  33 +- (id)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout {
  34 + if ( !(self = [super initWithFrame:frame collectionViewLayout:layout]) ) return nil;
  35 + [self setup];
  36 + return self;
  37 +}
  38 +
  39 +-(void)awakeFromNib {
  40 + [super awakeFromNib];
  41 + [self setup];
  42 +}
  43 +
  44 +-(void)dealloc {
  45 + [[NSNotificationCenter defaultCenter] removeObserver:self];
  46 +#if !__has_feature(objc_arc)
  47 + [super dealloc];
  48 +#endif
  49 +}
  50 +
  51 +
  52 +-(BOOL)hasAutomaticKeyboardAvoidingBehaviour {
  53 + if ( [[[UIDevice currentDevice] systemVersion] integerValue] >= 9
  54 + && [self.delegate isKindOfClass:[UICollectionViewController class]] ) {
  55 + // Theory: It looks like iOS 9's collection views automatically avoid the keyboard. As usual
  56 + // Apple have totally failed to document this anywhere, so this is just a guess.
  57 + return YES;
  58 + }
  59 +
  60 + return NO;
  61 +}
  62 +
  63 +-(void)setFrame:(CGRect)frame {
  64 + [super setFrame:frame];
  65 + [self TPKeyboardAvoiding_updateContentInset];
  66 +}
  67 +
  68 +-(void)setContentSize:(CGSize)contentSize {
  69 + if (CGSizeEqualToSize(contentSize, self.contentSize)) {
  70 + // Prevent triggering contentSize when it's already the same that
  71 + // cause weird infinte scrolling and locking bug
  72 + return;
  73 + }
  74 + [super setContentSize:contentSize];
  75 + [self TPKeyboardAvoiding_updateContentInset];
  76 +}
  77 +
  78 +- (BOOL)focusNextTextField {
  79 + return [self TPKeyboardAvoiding_focusNextTextField];
  80 +
  81 +}
  82 +- (void)scrollToActiveTextField {
  83 + return [self TPKeyboardAvoiding_scrollToActiveTextField];
  84 +}
  85 +
  86 +#pragma mark - Responders, events
  87 +
  88 +-(void)willMoveToSuperview:(UIView *)newSuperview {
  89 + [super willMoveToSuperview:newSuperview];
  90 + if ( !newSuperview ) {
  91 + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) object:self];
  92 + }
  93 +}
  94 +
  95 +- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
  96 + [[self TPKeyboardAvoiding_findFirstResponderBeneathView:self] resignFirstResponder];
  97 + [super touchesEnded:touches withEvent:event];
  98 +}
  99 +
  100 +-(BOOL)textFieldShouldReturn:(UITextField *)textField {
  101 + if ( ![self focusNextTextField] ) {
  102 + [textField resignFirstResponder];
  103 + }
  104 + return YES;
  105 +}
  106 +
  107 +-(void)layoutSubviews {
  108 + [super layoutSubviews];
  109 + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) object:self];
  110 + [self performSelector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) withObject:self afterDelay:0.1];
  111 +}
  112 +
  113 +@end
LifeLog/LifeLog/TPKeyboardAvoidingScrollView.h
  1 +//
  2 +// TPKeyboardAvoidingScrollView.h
  3 +// TPKeyboardAvoiding
  4 +//
  5 +// Created by Michael Tyson on 30/09/2013.
  6 +// Copyright 2015 A Tasty Pixel. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +#import "UIScrollView+TPKeyboardAvoidingAdditions.h"
  11 +
  12 +@interface TPKeyboardAvoidingScrollView : UIScrollView <UITextFieldDelegate, UITextViewDelegate>
  13 +- (void)contentSizeToFit;
  14 +- (BOOL)focusNextTextField;
  15 +- (void)scrollToActiveTextField;
  16 +@end
LifeLog/LifeLog/TPKeyboardAvoidingScrollView.m
  1 +//
  2 +// TPKeyboardAvoidingScrollView.m
  3 +// TPKeyboardAvoiding
  4 +//
  5 +// Created by Michael Tyson on 30/09/2013.
  6 +// Copyright 2015 A Tasty Pixel. All rights reserved.
  7 +//
  8 +
  9 +#import "TPKeyboardAvoidingScrollView.h"
  10 +
  11 +@interface TPKeyboardAvoidingScrollView () <UITextFieldDelegate, UITextViewDelegate>
  12 +@end
  13 +
  14 +@implementation TPKeyboardAvoidingScrollView
  15 +
  16 +#pragma mark - Setup/Teardown
  17 +
  18 +- (void)setup {
  19 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(TPKeyboardAvoiding_keyboardWillShow:) name:UIKeyboardWillChangeFrameNotification object:nil];
  20 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(TPKeyboardAvoiding_keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
  21 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollToActiveTextField) name:UITextViewTextDidBeginEditingNotification object:nil];
  22 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollToActiveTextField) name:UITextFieldTextDidBeginEditingNotification object:nil];
  23 +}
  24 +
  25 +-(id)initWithFrame:(CGRect)frame {
  26 + if ( !(self = [super initWithFrame:frame]) ) return nil;
  27 + [self setup];
  28 + return self;
  29 +}
  30 +
  31 +-(void)awakeFromNib {
  32 + [super awakeFromNib];
  33 + [self setup];
  34 +}
  35 +
  36 +-(void)dealloc {
  37 + [[NSNotificationCenter defaultCenter] removeObserver:self];
  38 +#if !__has_feature(objc_arc)
  39 + [super dealloc];
  40 +#endif
  41 +}
  42 +
  43 +-(void)setFrame:(CGRect)frame {
  44 + [super setFrame:frame];
  45 + [self TPKeyboardAvoiding_updateContentInset];
  46 +}
  47 +
  48 +-(void)setContentSize:(CGSize)contentSize {
  49 + [super setContentSize:contentSize];
  50 + [self TPKeyboardAvoiding_updateFromContentSizeChange];
  51 +}
  52 +
  53 +- (void)contentSizeToFit {
  54 + self.contentSize = [self TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames];
  55 +}
  56 +
  57 +- (BOOL)focusNextTextField {
  58 + return [self TPKeyboardAvoiding_focusNextTextField];
  59 +
  60 +}
  61 +- (void)scrollToActiveTextField {
  62 + return [self TPKeyboardAvoiding_scrollToActiveTextField];
  63 +}
  64 +
  65 +#pragma mark - Responders, events
  66 +
  67 +-(void)willMoveToSuperview:(UIView *)newSuperview {
  68 + [super willMoveToSuperview:newSuperview];
  69 + if ( !newSuperview ) {
  70 + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) object:self];
  71 + }
  72 +}
  73 +
  74 +- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
  75 + [[self TPKeyboardAvoiding_findFirstResponderBeneathView:self] resignFirstResponder];
  76 + [super touchesEnded:touches withEvent:event];
  77 +}
  78 +
  79 +-(BOOL)textFieldShouldReturn:(UITextField *)textField {
  80 + if ( ![self focusNextTextField] ) {
  81 + [textField resignFirstResponder];
  82 + }
  83 + return YES;
  84 +}
  85 +
  86 +-(void)layoutSubviews {
  87 + [super layoutSubviews];
  88 + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) object:self];
  89 + [self performSelector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) withObject:self afterDelay:0.1];
  90 +}
  91 +
  92 +@end
LifeLog/LifeLog/TPKeyboardAvoidingTableView.h
  1 +//
  2 +// TPKeyboardAvoidingTableView.h
  3 +// TPKeyboardAvoiding
  4 +//
  5 +// Created by Michael Tyson on 30/09/2013.
  6 +// Copyright 2015 A Tasty Pixel. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +#import "UIScrollView+TPKeyboardAvoidingAdditions.h"
  11 +
  12 +@interface TPKeyboardAvoidingTableView : UITableView <UITextFieldDelegate, UITextViewDelegate>
  13 +- (BOOL)focusNextTextField;
  14 +- (void)scrollToActiveTextField;
  15 +@end
LifeLog/LifeLog/TPKeyboardAvoidingTableView.m
  1 +//
  2 +// TPKeyboardAvoidingTableView.m
  3 +// TPKeyboardAvoiding
  4 +//
  5 +// Created by Michael Tyson on 30/09/2013.
  6 +// Copyright 2015 A Tasty Pixel. All rights reserved.