Skip to content

Commit de44184

Browse files
Andrei Shikovfacebook-github-bot
authored andcommitted
EditText: maintain cursor position when text changes
Summary: Similar to D29786190 (b0e39b2) on iOS, keeps cursor position constant to the end of the text whenever text changes without selection updates. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D29879663 fbshipit-source-id: da1b50a99ae3b9ef796423146ba49e4172e286df
1 parent efb359f commit de44184

File tree

2 files changed

+25
-2
lines changed

2 files changed

+25
-2
lines changed

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,10 +331,20 @@ public void maybeSetSelection(int eventCounter, int start, int end) {
331331
}
332332

333333
if (start != UNSET && end != UNSET) {
334+
// clamp selection values for safety
335+
start = clampToTextLength(start);
336+
end = clampToTextLength(end);
337+
334338
setSelection(start, end);
335339
}
336340
}
337341

342+
private int clampToTextLength(int value) {
343+
int textLength = getText() == null ? 0 : getText().length();
344+
345+
return Math.max(0, Math.min(value, textLength));
346+
}
347+
338348
@Override
339349
public void setSelection(int start, int end) {
340350
if (DEBUG_MODE) {

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,22 @@ public void updateExtraData(ReactEditText view, Object extraData) {
328328
Spannable spannable = update.getText();
329329
TextInlineImageSpan.possiblyUpdateInlineImageSpans(spannable, view);
330330
}
331+
332+
// Ensure that selection is handled correctly on text update
333+
boolean isCurrentSelectionEmpty = view.getSelectionStart() == view.getSelectionEnd();
334+
int selectionStart = update.getSelectionStart();
335+
int selectionEnd = update.getSelectionEnd();
336+
if ((selectionStart == UNSET || selectionEnd == UNSET) && isCurrentSelectionEmpty) {
337+
// if selection is not set by state, shift current selection to ensure constant gap to
338+
// text end
339+
int textLength = view.getText() == null ? 0 : view.getText().length();
340+
int selectionOffset = textLength - view.getSelectionStart();
341+
selectionStart = update.getText().length() - selectionOffset;
342+
selectionEnd = selectionStart;
343+
}
344+
331345
view.maybeSetTextFromState(update);
332-
view.maybeSetSelection(
333-
update.getJsEventCounter(), update.getSelectionStart(), update.getSelectionEnd());
346+
view.maybeSetSelection(update.getJsEventCounter(), selectionStart, selectionEnd);
334347
}
335348
}
336349

0 commit comments

Comments
 (0)