mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
fix(ios): avoid incorrectly updating caret position (#50680)
Summary: Avoid incorrectly updating caret position Pull Request resolved: https://github.com/facebook/react-native/issues/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: https://github.com/facebook/react-native/pull/50680 Test Plan: Tested with the following code(a simplified version from the code in https://github.com/facebook/react-native/issues/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
This commit is contained in:
committed by
Fabrizio Cucci
parent
f3c280442d
commit
89f4dd2a24
+22
-13
@@ -698,6 +698,11 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
|
||||
}
|
||||
|
||||
- (void)_restoreTextSelection
|
||||
{
|
||||
[self _restoreTextSelectionAndIgnoreCaretChange:NO];
|
||||
}
|
||||
|
||||
- (void)_restoreTextSelectionAndIgnoreCaretChange:(BOOL)ignore
|
||||
{
|
||||
const auto &selection = static_cast<const TextInputProps &>(*_props).selection;
|
||||
if (!selection.has_value()) {
|
||||
@@ -707,6 +712,9 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
|
||||
offset:selection->start];
|
||||
auto end = [_backedTextInputView positionFromPosition:_backedTextInputView.beginningOfDocument offset:selection->end];
|
||||
auto range = [_backedTextInputView textRangeFromPosition:start toPosition:end];
|
||||
if (ignore && range.empty) {
|
||||
return;
|
||||
}
|
||||
[_backedTextInputView setSelectedTextRange:range notifyDelegate:YES];
|
||||
}
|
||||
|
||||
@@ -721,19 +729,20 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
|
||||
// Updating the UITextView attributedText, for example changing the lineHeight, the color or adding
|
||||
// a new paragraph with \n, causes the cursor to move to the end of the Text and scroll.
|
||||
// This is fixed by restoring the cursor position and scrolling to that position (iOS issue 652653).
|
||||
if (selectedRange.empty) {
|
||||
// Maintaining a cursor position relative to the end of the old text.
|
||||
NSInteger offsetStart = [_backedTextInputView offsetFromPosition:_backedTextInputView.beginningOfDocument
|
||||
toPosition:selectedRange.start];
|
||||
NSInteger offsetFromEnd = oldTextLength - offsetStart;
|
||||
NSInteger newOffset = attributedString.string.length - offsetFromEnd;
|
||||
UITextPosition *position = [_backedTextInputView positionFromPosition:_backedTextInputView.beginningOfDocument
|
||||
offset:newOffset];
|
||||
[_backedTextInputView setSelectedTextRange:[_backedTextInputView textRangeFromPosition:position toPosition:position]
|
||||
notifyDelegate:YES];
|
||||
[_backedTextInputView scrollRangeToVisible:NSMakeRange(offsetStart, 0)];
|
||||
}
|
||||
[self _restoreTextSelection];
|
||||
// Maintaining a cursor position relative to the end of the old text.
|
||||
NSInteger offsetStart = [_backedTextInputView offsetFromPosition:_backedTextInputView.beginningOfDocument
|
||||
toPosition:selectedRange.start];
|
||||
NSInteger offsetFromEnd = oldTextLength - offsetStart;
|
||||
NSInteger newOffset = attributedString.string.length - offsetFromEnd;
|
||||
UITextPosition *position = [_backedTextInputView positionFromPosition:_backedTextInputView.beginningOfDocument
|
||||
offset:newOffset];
|
||||
[_backedTextInputView setSelectedTextRange:[_backedTextInputView textRangeFromPosition:position toPosition:position]
|
||||
notifyDelegate:YES];
|
||||
[_backedTextInputView scrollRangeToVisible:NSMakeRange(offsetStart, 0)];
|
||||
|
||||
// A zero-length selection range can cause the caret position to change on iOS,
|
||||
// and we have already updated the caret position, so we can safely ignore caret changing in this place.
|
||||
[self _restoreTextSelectionAndIgnoreCaretChange:YES];
|
||||
[self _updateTypingAttributes];
|
||||
_lastStringStateWasUpdatedWith = attributedString;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user