Skip to content

Commit 0bcf293

Browse files
NickGerlemankelset
authored andcommittedApr 19, 2023
Fix measurement of uncontrolled TextInput after edit
Summary: D42721684 (be69c8b) left a pretty bad bug when using Fabric for Android. I missed that in Fabric specifically, on edit we will cache the Spannable backing the EditText for use in future measurement. Because we've stripped the sizing spans, Spannable measurement has incorrect font size, and the TextInput size will change (collapsing) after the first edit. This effectively breaks any uncontrolled TextInput which does not have explicit dimensions set. Changelog: [Android][Fixed] - Fix measurement of uncontrolled TextInput after edit Reviewed By: sammy-SC Differential Revision: D43158407 fbshipit-source-id: 51602eab06c9a50e2b60ef0ed87bdb4df025e51e
1 parent f4f3aa3 commit 0bcf293

File tree

1 file changed

+29
-3
lines changed

1 file changed

+29
-3
lines changed
 

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

+29-3
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ public void maybeSetText(ReactTextUpdate reactTextUpdate) {
552552
manageSpans(spannableStringBuilder, reactTextUpdate.mContainsMultipleFragments);
553553

554554
// Mitigation for https://github.com/facebook/react-native/issues/35936 (S318090)
555-
stripAbsoluteSizeSpans(spannableStringBuilder);
555+
stripAtributeEquivalentSpans(spannableStringBuilder);
556556

557557
mContainsImages = reactTextUpdate.containsImages();
558558

@@ -627,7 +627,7 @@ private void manageSpans(
627627
}
628628
}
629629

630-
private void stripAbsoluteSizeSpans(SpannableStringBuilder sb) {
630+
private void stripAtributeEquivalentSpans(SpannableStringBuilder sb) {
631631
// We have already set a font size on the EditText itself. We can safely remove sizing spans
632632
// which are the same as the set font size, and not otherwise overlapped.
633633
final int effectiveFontSize = mTextAttributes.getEffectiveFontSize();
@@ -648,6 +648,31 @@ private void stripAbsoluteSizeSpans(SpannableStringBuilder sb) {
648648
}
649649
}
650650

651+
private void unstripAttributeEquivalentSpans(
652+
SpannableStringBuilder workingText, Spannable originalText) {
653+
// We must add spans back for Fabric to be able to measure, at lower precedence than any
654+
// existing spans. Remove all spans, add the attributes, then re-add the spans over
655+
workingText.append(originalText);
656+
657+
for (Object span : workingText.getSpans(0, workingText.length(), Object.class)) {
658+
workingText.removeSpan(span);
659+
}
660+
661+
workingText.setSpan(
662+
new ReactAbsoluteSizeSpan(mTextAttributes.getEffectiveFontSize()),
663+
0,
664+
workingText.length(),
665+
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
666+
667+
for (Object span : originalText.getSpans(0, originalText.length(), Object.class)) {
668+
workingText.setSpan(
669+
span,
670+
originalText.getSpanStart(span),
671+
originalText.getSpanEnd(span),
672+
originalText.getSpanFlags(span));
673+
}
674+
}
675+
651676
private static boolean sameTextForSpan(
652677
final Editable oldText,
653678
final SpannableStringBuilder newText,
@@ -1066,7 +1091,8 @@ private void updateCachedSpannable(boolean resetStyles) {
10661091
// ...
10671092
// - android.app.Activity.dispatchKeyEvent (Activity.java:3447)
10681093
try {
1069-
sb.append(currentText.subSequence(0, currentText.length()));
1094+
Spannable text = (Spannable) currentText.subSequence(0, currentText.length());
1095+
unstripAttributeEquivalentSpans(sb, text);
10701096
} catch (IndexOutOfBoundsException e) {
10711097
ReactSoftExceptionLogger.logSoftException(TAG, e);
10721098
}

0 commit comments

Comments
 (0)
Please sign in to comment.