forked from facebook/react-native
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introducing
RCTBackedTextInputDelegate
Summary: Nothing behavioral changed in this diff; just moving code around. `RCTBackedTextInputDelegate` is the new protocol which supposed to be common determinator among of UITextFieldDelegate and UITextViewDelegate (and bunch of events and notifications around UITextInput and UITextView). We need this reach two goals in the future: * Incapsulate UIKit imperfections related hack in dedicated protocol adapter. So, doing this we can fix more UIKit related bugs without touching real RN text handling logic. (Yes, we still have a bunch of bugs, which we cannot fix because it is undoable with the current architecture. This diff does NOT fix anything though.) * We can unify logic in RCTTextField and RCTTextView (even more!), moving it to a superclass. If we do so, we can fix another bunch of bugs related to RN imperfections. And have singleline/multiline inputs implementations even more consistent. Reviewed By: mmmulani Differential Revision: D5296041 fbshipit-source-id: 318fd850e946a3c34933002a6bde34a0a45a6293
- Loading branch information
1 parent
2a7bde0
commit ee9697e
Showing
15 changed files
with
460 additions
and
209 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
*/ | ||
|
||
#import <UIKit/UIKit.h> | ||
|
||
@protocol RCTBackedTextInputViewProtocol; | ||
|
||
@protocol RCTBackedTextInputDelegate <NSObject> | ||
|
||
- (BOOL)textInputShouldBeginEditing; // Return `NO` to disallow editing. | ||
- (void)textInputDidBeginEditing; | ||
|
||
- (BOOL)textInputShouldEndEditing; // Return `YES` to allow editing to stop and to resign first responder status. `NO` to disallow the editing session to end. | ||
- (void)textInputDidEndEditing; // May be called if forced even if `textInputShouldEndEditing` returns `NO` (e.g. view removed from window) or `[textInput endEditing:YES]` called. | ||
- (void)textInputDidEndEditingOnExit; // May be called right before `textInputShouldEndEditing` if "Submit" button was pressed. | ||
|
||
- (BOOL)textInputShouldChangeTextInRange:(NSRange)range replacementText:(NSString *)string; // Return NO to not change text. | ||
- (void)textInputDidChange; | ||
|
||
- (void)textInputDidChangeSelection; | ||
|
||
@end |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
*/ | ||
|
||
#import <UIKit/UIKit.h> | ||
|
||
#import "RCTBackedTextInputViewProtocol.h" | ||
#import "RCTBackedTextInputDelegate.h" | ||
|
||
#pragma mark - RCTBackedTextFieldDelegateAdapter (for UITextField) | ||
|
||
@interface RCTBackedTextFieldDelegateAdapter : NSObject | ||
|
||
- (instancetype)initWithTextField:(UITextField<RCTBackedTextInputViewProtocol> *)backedTextInput; | ||
|
||
@end | ||
|
||
#pragma mark - RCTBackedTextViewDelegateAdapter (for UITextView) | ||
|
||
@interface RCTBackedTextViewDelegateAdapter : NSObject | ||
|
||
- (instancetype)initWithTextView:(UITextView<RCTBackedTextInputViewProtocol> *)backedTextInput; | ||
|
||
@end |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
/** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
*/ | ||
|
||
#import "RCTBackedTextInputDelegateAdapter.h" | ||
|
||
#pragma mark - RCTBackedTextFieldDelegateAdapter (for UITextField) | ||
|
||
static void *TextFieldSelectionObservingContext = &TextFieldSelectionObservingContext; | ||
|
||
@interface RCTBackedTextFieldDelegateAdapter () <UITextFieldDelegate> | ||
@end | ||
|
||
@implementation RCTBackedTextFieldDelegateAdapter { | ||
__weak UITextField<RCTBackedTextInputViewProtocol> *_backedTextInput; | ||
__unsafe_unretained UITextField<RCTBackedTextInputViewProtocol> *_unsafeBackedTextInput; | ||
} | ||
|
||
- (instancetype)initWithTextField:(UITextField<RCTBackedTextInputViewProtocol> *)backedTextInput | ||
{ | ||
if (self = [super init]) { | ||
_backedTextInput = backedTextInput; | ||
_unsafeBackedTextInput = backedTextInput; | ||
backedTextInput.delegate = self; | ||
|
||
[_backedTextInput addTarget:self action:@selector(textFieldDidChange) forControlEvents:UIControlEventEditingChanged]; | ||
[_backedTextInput addTarget:self action:@selector(textFieldDidEndEditingOnExit) forControlEvents:UIControlEventEditingDidEndOnExit]; | ||
|
||
// We have to use `unsafe_unretained` pointer to `backedTextInput` for subscribing (and especially unsubscribing) for it | ||
// because `weak` pointers do not KVO complient, unfortunately. | ||
[_unsafeBackedTextInput addObserver:self forKeyPath:@"selectedTextRange" options:0 context:TextFieldSelectionObservingContext]; | ||
} | ||
|
||
return self; | ||
} | ||
|
||
- (void)dealloc | ||
{ | ||
[_backedTextInput removeTarget:self action:nil forControlEvents:UIControlEventEditingChanged]; | ||
[_backedTextInput removeTarget:self action:nil forControlEvents:UIControlEventEditingDidEndOnExit]; | ||
[_unsafeBackedTextInput removeObserver:self forKeyPath:@"selectedTextRange" context:TextFieldSelectionObservingContext]; | ||
} | ||
|
||
#pragma mark - UITextFieldDelegate | ||
|
||
- (BOOL)textFieldShouldBeginEditing:(__unused UITextField *)textField | ||
{ | ||
return [_backedTextInput.textInputDelegate textInputShouldBeginEditing]; | ||
} | ||
|
||
- (void)textFieldDidBeginEditing:(__unused UITextField *)textField | ||
{ | ||
[_backedTextInput.textInputDelegate textInputDidBeginEditing]; | ||
} | ||
|
||
- (BOOL)textFieldShouldEndEditing:(__unused UITextField *)textField | ||
{ | ||
return [_backedTextInput.textInputDelegate textInputShouldEndEditing]; | ||
} | ||
|
||
- (void)textFieldDidEndEditing:(__unused UITextField *)textField | ||
{ | ||
[_backedTextInput.textInputDelegate textInputDidEndEditing]; | ||
} | ||
|
||
- (BOOL)textField:(__unused UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string | ||
{ | ||
return [_backedTextInput.textInputDelegate textInputShouldChangeTextInRange:range replacementText:string]; | ||
} | ||
|
||
#pragma mark - Key Value Observing | ||
|
||
- (void)observeValueForKeyPath:(NSString *)keyPath | ||
ofObject:(nullable id)object | ||
change:(NSDictionary *)change | ||
context:(void *)context | ||
{ | ||
if (context == TextFieldSelectionObservingContext) { | ||
if ([keyPath isEqualToString:@"selectedTextRange"]) { | ||
[_backedTextInput.textInputDelegate textInputDidChangeSelection]; | ||
} | ||
|
||
return; | ||
} | ||
|
||
[super observeValueForKeyPath:keyPath | ||
ofObject:object | ||
change:change | ||
context:context]; | ||
} | ||
|
||
#pragma mark - UIControlEventEditing* Family Events | ||
|
||
- (void)textFieldDidChange | ||
{ | ||
[_backedTextInput.textInputDelegate textInputDidChange]; | ||
} | ||
|
||
- (void)textFieldDidEndEditingOnExit | ||
{ | ||
[_backedTextInput.textInputDelegate textInputDidEndEditingOnExit]; | ||
} | ||
|
||
#pragma mark - UIKeyboardInput (private UIKit protocol) | ||
|
||
// This method allows us to detect a [Backspace] `keyPress` | ||
// even when there is no more text in the `UITextField`. | ||
- (BOOL)keyboardInputShouldDelete:(__unused UITextField *)textField | ||
{ | ||
[_backedTextInput.textInputDelegate textInputShouldChangeTextInRange:NSMakeRange(0, 0) replacementText:@""]; | ||
return YES; | ||
} | ||
|
||
@end | ||
|
||
#pragma mark - RCTBackedTextViewDelegateAdapter (for UITextView) | ||
|
||
@interface RCTBackedTextViewDelegateAdapter () <UITextViewDelegate> | ||
@end | ||
|
||
@implementation RCTBackedTextViewDelegateAdapter { | ||
__weak UITextView<RCTBackedTextInputViewProtocol> *_backedTextInput; | ||
} | ||
|
||
- (instancetype)initWithTextView:(UITextView<RCTBackedTextInputViewProtocol> *)backedTextInput | ||
{ | ||
if (self = [super init]) { | ||
_backedTextInput = backedTextInput; | ||
backedTextInput.delegate = self; | ||
} | ||
|
||
return self; | ||
} | ||
|
||
#pragma mark - UITextViewDelegate | ||
|
||
- (BOOL)textViewShouldBeginEditing:(__unused UITextView *)textView | ||
{ | ||
return [_backedTextInput.textInputDelegate textInputShouldBeginEditing]; | ||
} | ||
|
||
- (void)textViewDidBeginEditing:(__unused UITextView *)textView | ||
{ | ||
[_backedTextInput.textInputDelegate textInputDidBeginEditing]; | ||
} | ||
|
||
- (BOOL)textViewShouldEndEditing:(__unused UITextView *)textView | ||
{ | ||
return [_backedTextInput.textInputDelegate textInputShouldEndEditing]; | ||
} | ||
|
||
- (void)textViewDidEndEditing:(__unused UITextView *)textView | ||
{ | ||
[_backedTextInput.textInputDelegate textInputDidEndEditing]; | ||
} | ||
|
||
- (BOOL)textView:(__unused UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text | ||
{ | ||
return [_backedTextInput.textInputDelegate textInputShouldChangeTextInRange:range replacementText:text]; | ||
} | ||
|
||
- (void)textViewDidChange:(__unused UITextView *)textView | ||
{ | ||
[_backedTextInput.textInputDelegate textInputDidChange]; | ||
} | ||
|
||
- (void)textViewDidChangeSelection:(__unused UITextView *)textView | ||
{ | ||
[_backedTextInput.textInputDelegate textInputDidChangeSelection]; | ||
} | ||
|
||
@end |
This file contains 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
This file contains 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
This file contains 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
Oops, something went wrong.