EditText: maintain cursor position when text changes

Summary:
Similar to D29786190 (https://github.com/facebook/react-native/commit/b0e39b2ed9b66b378eb75bee9e692fc801431ddd) 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
This commit is contained in:
Andrei Shikov
2021-07-23 14:29:11 -07:00
committed by Facebook GitHub Bot
parent efb359f318
commit de44184e01
2 changed files with 25 additions and 2 deletions
@@ -331,10 +331,20 @@ public class ReactEditText extends AppCompatEditText
}
if (start != UNSET && end != UNSET) {
// clamp selection values for safety
start = clampToTextLength(start);
end = clampToTextLength(end);
setSelection(start, end);
}
}
private int clampToTextLength(int value) {
int textLength = getText() == null ? 0 : getText().length();
return Math.max(0, Math.min(value, textLength));
}
@Override
public void setSelection(int start, int end) {
if (DEBUG_MODE) {
@@ -328,9 +328,22 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
Spannable spannable = update.getText();
TextInlineImageSpan.possiblyUpdateInlineImageSpans(spannable, view);
}
// Ensure that selection is handled correctly on text update
boolean isCurrentSelectionEmpty = view.getSelectionStart() == view.getSelectionEnd();
int selectionStart = update.getSelectionStart();
int selectionEnd = update.getSelectionEnd();
if ((selectionStart == UNSET || selectionEnd == UNSET) && isCurrentSelectionEmpty) {
// if selection is not set by state, shift current selection to ensure constant gap to
// text end
int textLength = view.getText() == null ? 0 : view.getText().length();
int selectionOffset = textLength - view.getSelectionStart();
selectionStart = update.getText().length() - selectionOffset;
selectionEnd = selectionStart;
}
view.maybeSetTextFromState(update);
view.maybeSetSelection(
update.getJsEventCounter(), update.getSelectionStart(), update.getSelectionEnd());
view.maybeSetSelection(update.getJsEventCounter(), selectionStart, selectionEnd);
}
}