Skip to content

Commit 8a0fe30

Browse files
NickGerlemanfacebook-github-bot
authored andcommitted
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 97d90c6 commit 8a0fe30

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
@@ -587,7 +587,7 @@ public void maybeSetText(ReactTextUpdate reactTextUpdate) {
587587
manageSpans(spannableStringBuilder, reactTextUpdate.mContainsMultipleFragments);
588588

589589
// Mitigation for https://github.com/facebook/react-native/issues/35936 (S318090)
590-
stripAbsoluteSizeSpans(spannableStringBuilder);
590+
stripAtributeEquivalentSpans(spannableStringBuilder);
591591

592592
mContainsImages = reactTextUpdate.containsImages();
593593

@@ -662,7 +662,7 @@ private void manageSpans(
662662
}
663663
}
664664

665-
private void stripAbsoluteSizeSpans(SpannableStringBuilder sb) {
665+
private void stripAtributeEquivalentSpans(SpannableStringBuilder sb) {
666666
// We have already set a font size on the EditText itself. We can safely remove sizing spans
667667
// which are the same as the set font size, and not otherwise overlapped.
668668
final int effectiveFontSize = mTextAttributes.getEffectiveFontSize();
@@ -683,6 +683,31 @@ private void stripAbsoluteSizeSpans(SpannableStringBuilder sb) {
683683
}
684684
}
685685

686+
private void unstripAttributeEquivalentSpans(
687+
SpannableStringBuilder workingText, Spannable originalText) {
688+
// We must add spans back for Fabric to be able to measure, at lower precedence than any
689+
// existing spans. Remove all spans, add the attributes, then re-add the spans over
690+
workingText.append(originalText);
691+
692+
for (Object span : workingText.getSpans(0, workingText.length(), Object.class)) {
693+
workingText.removeSpan(span);
694+
}
695+
696+
workingText.setSpan(
697+
new ReactAbsoluteSizeSpan(mTextAttributes.getEffectiveFontSize()),
698+
0,
699+
workingText.length(),
700+
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
701+
702+
for (Object span : originalText.getSpans(0, originalText.length(), Object.class)) {
703+
workingText.setSpan(
704+
span,
705+
originalText.getSpanStart(span),
706+
originalText.getSpanEnd(span),
707+
originalText.getSpanFlags(span));
708+
}
709+
}
710+
686711
private static boolean sameTextForSpan(
687712
final Editable oldText,
688713
final SpannableStringBuilder newText,
@@ -1102,7 +1127,8 @@ private void updateCachedSpannable(boolean resetStyles) {
11021127
// ...
11031128
// - android.app.Activity.dispatchKeyEvent (Activity.java:3447)
11041129
try {
1105-
sb.append(currentText.subSequence(0, currentText.length()));
1130+
Spannable text = (Spannable) currentText.subSequence(0, currentText.length());
1131+
unstripAttributeEquivalentSpans(sb, text);
11061132
} catch (IndexOutOfBoundsException e) {
11071133
ReactSoftExceptionLogger.logSoftException(TAG, e);
11081134
}

0 commit comments

Comments
 (0)