diff --git a/Libraries/Text/RCTTextView.m b/Libraries/Text/RCTTextView.m index 6b2880eff..f4329d0ef 100644 --- a/Libraries/Text/RCTTextView.m +++ b/Libraries/Text/RCTTextView.m @@ -489,6 +489,35 @@ static BOOL findMismatch(NSString *first, NSString *second, NSRange *firstRange, _nativeUpdatesInFlight = NO; _nativeEventCount++; + + // TODO: t16435709 This part will be removed soon. + if (!self.reactTag || !_onChange) { + return; + } + + // When the context size increases, iOS updates the contentSize twice; once + // with a lower height, then again with the correct height. To prevent a + // spurious event from being sent, we track the previous, and only send the + // update event if it matches our expectation that greater text length + // should result in increased height. This assumption is, of course, not + // necessarily true because shorter text might include more linebreaks, but + // in practice this works well enough. + NSUInteger textLength = textView.text.length; + CGFloat contentHeight = textView.contentSize.height; + if (textLength >= _previousTextLength) { + contentHeight = MAX(contentHeight, _previousContentHeight); + } + _previousTextLength = textLength; + _previousContentHeight = contentHeight; + _onChange(@{ + @"text": self.text, + @"contentSize": @{ + @"height": @(contentHeight), + @"width": @(textView.contentSize.width) + }, + @"target": self.reactTag, + @"eventCount": @(_nativeEventCount), + }); } - (void)textViewDidEndEditing:(UITextView *)textView diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextChangedEvent.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextChangedEvent.java index 7b9f2829b..67ca37c5e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextChangedEvent.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextChangedEvent.java @@ -23,14 +23,20 @@ public class ReactTextChangedEvent extends Event { public static final String EVENT_NAME = "topChange"; private String mText; + private float mContentWidth; + private float mContentHeight; private int mEventCount; public ReactTextChangedEvent( int viewId, String text, + float contentSizeWidth, + float contentSizeHeight, int eventCount) { super(viewId); mText = text; + mContentWidth = contentSizeWidth; + mContentHeight = contentSizeHeight; mEventCount = eventCount; } @@ -47,7 +53,13 @@ public class ReactTextChangedEvent extends Event { private WritableMap serializeEventData() { WritableMap eventData = Arguments.createMap(); eventData.putString("text", mText); + + WritableMap contentSize = Arguments.createMap(); + contentSize.putDouble("width", mContentWidth); + contentSize.putDouble("height", mContentHeight); + eventData.putMap("contentSize", contentSize); eventData.putInt("eventCount", mEventCount); + eventData.putInt("target", getViewTag()); return eventData; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java index 24189fc4e..c464ec528 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java @@ -683,12 +683,26 @@ public class ReactTextInputManager extends BaseViewManager