Files
braintree-ios-drop-in/BraintreeUIKit/Components/BTUIKTextField.m
2016-09-23 10:31:01 -05:00

123 lines
4.3 KiB
Objective-C

#import "BTUIKTextField.h"
#import "BTUIKInputAccessoryToolbar.h"
#import "BTUIKAppearance.h"
#import "BTUIKViewUtil.h"
@interface BTUIKTextField () <UITextFieldDelegate>
@property (nonatomic, copy) NSString *previousText;
@end
@implementation BTUIKTextField
- (instancetype)init {
if (self = [super init]) {
self.hideCaret = NO;
if ([UIDevice currentDevice].systemVersion.intValue == 9) {
[self addTarget:self action:@selector(iOS9_changed) forControlEvents:UIControlEventEditingChanged];
self.delegate = self;
}
}
return self;
}
- (void)setPlaceholder:(NSString *)placeholder {
NSMutableAttributedString *mutablePlaceholder = [[NSMutableAttributedString alloc] initWithString:placeholder];
[mutablePlaceholder beginEditing];
[mutablePlaceholder addAttributes:@{NSForegroundColorAttributeName: [BTUIKAppearance sharedInstance].placeholderTextColor, NSFontAttributeName:[UIFont fontWithName:[BTUIKAppearance sharedInstance].fontFamily size:[UIFont labelFontSize]]} range:NSMakeRange(0, [mutablePlaceholder length])];
[mutablePlaceholder endEditing];
self.attributedPlaceholder = mutablePlaceholder;
}
- (void)iOS9_changed {
// We only want to notify when this text field's text length has increased
if (self.previousText.length >= self.text.length) {
self.previousText = self.text;
return;
}
self.previousText = self.text;
NSString *insertedText = [self.text substringWithRange:NSMakeRange(self.previousText.length, self.text.length - self.previousText.length)];
if ([self.editDelegate respondsToSelector:@selector(textField:willInsertText:)]) {
// Sets _backspace = NO; in the BTUIKFormField or BTUIKFormField subclass
[self.editDelegate textField:self willInsertText:insertedText];
}
self.previousText = self.text;
if ([self.editDelegate respondsToSelector:@selector(textField:didInsertText:)]) {
[self.editDelegate textField:self didInsertText:insertedText];
}
}
- (BOOL)keyboardInputShouldDelete:(__unused UITextField *)textField {
if ([self.editDelegate respondsToSelector:@selector(textFieldWillDeleteBackward:)]) {
[self.editDelegate textFieldWillDeleteBackward:self];
}
BOOL shouldDelete = YES;
if ([UITextField instancesRespondToSelector:_cmd]) {
BOOL (*keyboardInputShouldDelete)(id, SEL, UITextField *) = (BOOL (*)(id, SEL, UITextField *))[UITextField instanceMethodForSelector:_cmd];
if (keyboardInputShouldDelete) {
shouldDelete = keyboardInputShouldDelete(self, _cmd, textField);
}
}
BOOL isIos8 = ([[[UIDevice currentDevice] systemVersion] intValue] == 8);
BOOL isLessThanIos8_3 = ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.3f);
// iOS 8.0-8.2 has a bug where deleteBackward is not called even when this method returns YES and the character is deleted
// As a result, we do so manually but return NO in order to prevent UITextField from double-calling the delegate method
// (textFieldDidDeleteBackwards:originalText:)
if (isIos8 && isLessThanIos8_3) {
[self deleteBackward];
shouldDelete = NO;
}
return shouldDelete;
}
- (void)deleteBackward
{
BOOL shouldDismiss = [self.text length] == 0;
NSString *originalText = self.text;
[super deleteBackward];
if (shouldDismiss) {
if ([self.delegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
[self.delegate textField:self shouldChangeCharactersInRange:NSMakeRange(0, 0) replacementString:@""];
}
}
if ([self.editDelegate respondsToSelector:@selector(textFieldDidDeleteBackward:originalText:)]) {
[self.editDelegate textFieldDidDeleteBackward:self originalText:originalText];
}
}
- (void)insertText:(NSString *)text {
if ([self.editDelegate respondsToSelector:@selector(textField:willInsertText:)]) {
[self.editDelegate textField:self willInsertText:text];
}
[super insertText:text];
if ([self.editDelegate respondsToSelector:@selector(textField:didInsertText:)]) {
[self.editDelegate textField:self didInsertText:text];
}
}
- (CGRect)caretRectForPosition:(UITextPosition *)position
{
if (self.hideCaret) {
return CGRectZero;
}
return [super caretRectForPosition:position];
}
@end