Skip to content

Commit 89f4dd2

Browse files
ouchuanfabriziocucci
authored andcommitted
fix(ios): avoid incorrectly updating caret position (#50680)
Summary: Avoid incorrectly updating caret position Pull Request resolved: #50641 The caret position is updated incorrectly when a user is first typing if an zero-length selection is set. [IOS] [CHANGED] - Typing into TextInput now will not cause the caret position to update to the beginning when a zero-length selection is set. Pull Request resolved: #50680 Test Plan: Tested with the following code(a simplified version from the code in #50641) ```js const [selection, setSelection] = useState({start: -1, end: -1}); const onSelectionChange = ( evt: NativeSyntheticEvent<TextInputSelectionChangeEventData>, ) => { const {selection} = evt.nativeEvent; const {start, end} = selection; console.log('selection change: ', start, end); setSelection(selection); }; return ( <View style={{ position: 'absolute', top: 50, left: 30 }}> <TextInput placeholder="test" selection={selection} onSelectionChange={onSelectionChange} /> </View> ); ``` When using the main branch, the caret position will jump back to the beginning after the first typing. It works fine after applying this commit. Reviewed By: fabriziocucci Differential Revision: D72957245 Pulled By: cipolleschi fbshipit-source-id: 3586797332b35e86b17f386a35e7d192ff758f7e
1 parent f3c2804 commit 89f4dd2

File tree

1 file changed

+22
-13
lines changed

1 file changed

+22
-13
lines changed

packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm

+22-13
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,11 @@ - (void)_updateState
698698
}
699699

700700
- (void)_restoreTextSelection
701+
{
702+
[self _restoreTextSelectionAndIgnoreCaretChange:NO];
703+
}
704+
705+
- (void)_restoreTextSelectionAndIgnoreCaretChange:(BOOL)ignore
701706
{
702707
const auto &selection = static_cast<const TextInputProps &>(*_props).selection;
703708
if (!selection.has_value()) {
@@ -707,6 +712,9 @@ - (void)_restoreTextSelection
707712
offset:selection->start];
708713
auto end = [_backedTextInputView positionFromPosition:_backedTextInputView.beginningOfDocument offset:selection->end];
709714
auto range = [_backedTextInputView textRangeFromPosition:start toPosition:end];
715+
if (ignore && range.empty) {
716+
return;
717+
}
710718
[_backedTextInputView setSelectedTextRange:range notifyDelegate:YES];
711719
}
712720

@@ -721,19 +729,20 @@ - (void)_setAttributedString:(NSAttributedString *)attributedString
721729
// Updating the UITextView attributedText, for example changing the lineHeight, the color or adding
722730
// a new paragraph with \n, causes the cursor to move to the end of the Text and scroll.
723731
// This is fixed by restoring the cursor position and scrolling to that position (iOS issue 652653).
724-
if (selectedRange.empty) {
725-
// Maintaining a cursor position relative to the end of the old text.
726-
NSInteger offsetStart = [_backedTextInputView offsetFromPosition:_backedTextInputView.beginningOfDocument
727-
toPosition:selectedRange.start];
728-
NSInteger offsetFromEnd = oldTextLength - offsetStart;
729-
NSInteger newOffset = attributedString.string.length - offsetFromEnd;
730-
UITextPosition *position = [_backedTextInputView positionFromPosition:_backedTextInputView.beginningOfDocument
731-
offset:newOffset];
732-
[_backedTextInputView setSelectedTextRange:[_backedTextInputView textRangeFromPosition:position toPosition:position]
733-
notifyDelegate:YES];
734-
[_backedTextInputView scrollRangeToVisible:NSMakeRange(offsetStart, 0)];
735-
}
736-
[self _restoreTextSelection];
732+
// Maintaining a cursor position relative to the end of the old text.
733+
NSInteger offsetStart = [_backedTextInputView offsetFromPosition:_backedTextInputView.beginningOfDocument
734+
toPosition:selectedRange.start];
735+
NSInteger offsetFromEnd = oldTextLength - offsetStart;
736+
NSInteger newOffset = attributedString.string.length - offsetFromEnd;
737+
UITextPosition *position = [_backedTextInputView positionFromPosition:_backedTextInputView.beginningOfDocument
738+
offset:newOffset];
739+
[_backedTextInputView setSelectedTextRange:[_backedTextInputView textRangeFromPosition:position toPosition:position]
740+
notifyDelegate:YES];
741+
[_backedTextInputView scrollRangeToVisible:NSMakeRange(offsetStart, 0)];
742+
743+
// A zero-length selection range can cause the caret position to change on iOS,
744+
// and we have already updated the caret position, so we can safely ignore caret changing in this place.
745+
[self _restoreTextSelectionAndIgnoreCaretChange:YES];
737746
[self _updateTypingAttributes];
738747
_lastStringStateWasUpdatedWith = attributedString;
739748
}

0 commit comments

Comments
 (0)