diff --git a/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m b/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m index dc19ed63e4a0a0..75421035523c78 100644 --- a/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m +++ b/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m @@ -16,6 +16,7 @@ @interface RCTBackedTextFieldDelegateAdapter () @implementation RCTBackedTextFieldDelegateAdapter { __weak UITextField *_backedTextInputView; + BOOL _textDidChangeIsComing; UITextRange *_previousSelectedTextRange; } @@ -57,12 +58,22 @@ - (BOOL)textFieldShouldEndEditing:(__unused UITextField *)textField - (void)textFieldDidEndEditing:(__unused UITextField *)textField { + if (_textDidChangeIsComing) { + // iOS does't call `textViewDidChange:` delegate method if the change was happened because of autocorrection + // which was triggered by losing focus. So, we call it manually. + _textDidChangeIsComing = NO; + [_backedTextInputView.textInputDelegate textInputDidChange]; + } + [_backedTextInputView.textInputDelegate textInputDidEndEditing]; } - (BOOL)textField:(__unused UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { BOOL result = [_backedTextInputView.textInputDelegate textInputShouldChangeTextInRange:range replacementText:string]; + if (result) { + _textDidChangeIsComing = YES; + } return result; } @@ -75,7 +86,9 @@ - (BOOL)textFieldShouldReturn:(__unused UITextField *)textField - (void)textFieldDidChange { + _textDidChangeIsComing = NO; [_backedTextInputView.textInputDelegate textInputDidChange]; + // `selectedTextRangeWasSet` isn't triggered during typing. [self textFieldProbablyDidChangeSelection]; } @@ -123,11 +136,12 @@ - (void)textFieldProbablyDidChangeSelection #pragma mark - RCTBackedTextViewDelegateAdapter (for UITextView) -@interface RCTBackedTextViewDelegateAdapter () +@interface RCTBackedTextViewDelegateAdapter () @end @implementation RCTBackedTextViewDelegateAdapter { __weak UITextView *_backedTextInputView; + BOOL _textDidChangeIsComing; UITextRange *_previousSelectedTextRange; } @@ -136,21 +150,11 @@ - (instancetype)initWithTextView:(UITextView *)b if (self = [super init]) { _backedTextInputView = backedTextInputView; backedTextInputView.delegate = self; - backedTextInputView.textStorage.delegate = self; } return self; } -#pragma mark - -- (void)textStorage:(NSTextStorage *)textStorage - didProcessEditing:(__unused NSTextStorageEditActions)editedMask - range:(__unused NSRange)editedRange - changeInLength:(__unused NSInteger)delta { - [_backedTextInputView.textInputDelegate textInputDidChange]; -} - - #pragma mark - UITextViewDelegate - (BOOL)textViewShouldBeginEditing:(__unused UITextView *)textView @@ -170,6 +174,13 @@ - (BOOL)textViewShouldEndEditing:(__unused UITextView *)textView - (void)textViewDidEndEditing:(__unused UITextView *)textView { + if (_textDidChangeIsComing) { + // iOS does't call `textViewDidChange:` delegate method if the change was happened because of autocorrection + // which was triggered by losing focus. So, we call it manually. + _textDidChangeIsComing = NO; + [_backedTextInputView.textInputDelegate textInputDidChange]; + } + [_backedTextInputView.textInputDelegate textInputDidEndEditing]; } @@ -185,9 +196,18 @@ - (BOOL)textView:(__unused UITextView *)textView shouldChangeTextInRange:(NSRang } BOOL result = [_backedTextInputView.textInputDelegate textInputShouldChangeTextInRange:range replacementText:text]; + if (result) { + _textDidChangeIsComing = YES; + } return result; } +- (void)textViewDidChange:(__unused UITextView *)textView +{ + _textDidChangeIsComing = NO; + [_backedTextInputView.textInputDelegate textInputDidChange]; +} + - (void)textViewDidChangeSelection:(__unused UITextView *)textView { [self textViewProbablyDidChangeSelection];