64
64
import com .facebook .react .views .text .TextLayoutManager ;
65
65
import com .facebook .react .views .view .ReactViewBackgroundManager ;
66
66
import java .util .ArrayList ;
67
- import java .util .List ;
68
67
import java .util .Objects ;
69
68
70
69
/**
@@ -89,7 +88,6 @@ public class ReactEditText extends AppCompatEditText
89
88
// *TextChanged events should be triggered. This is less expensive than removing the text
90
89
// listeners and adding them back again after the text change is completed.
91
90
protected boolean mIsSettingTextFromJS ;
92
- protected boolean mIsSettingTextFromCacheUpdate = false ;
93
91
private int mDefaultGravityHorizontal ;
94
92
private int mDefaultGravityVertical ;
95
93
@@ -369,7 +367,7 @@ protected void onSelectionChanged(int selStart, int selEnd) {
369
367
}
370
368
371
369
super .onSelectionChanged (selStart , selEnd );
372
- if (! mIsSettingTextFromCacheUpdate && mSelectionWatcher != null && hasFocus ()) {
370
+ if (mSelectionWatcher != null && hasFocus ()) {
373
371
mSelectionWatcher .onSelectionChanged (selStart , selEnd );
374
372
}
375
373
}
@@ -610,7 +608,7 @@ public void maybeSetText(ReactTextUpdate reactTextUpdate) {
610
608
SpannableStringBuilder spannableStringBuilder =
611
609
new SpannableStringBuilder (reactTextUpdate .getText ());
612
610
613
- manageSpans (spannableStringBuilder , reactTextUpdate . mContainsMultipleFragments );
611
+ manageSpans (spannableStringBuilder );
614
612
stripStyleEquivalentSpans (spannableStringBuilder );
615
613
616
614
mContainsImages = reactTextUpdate .containsImages ();
@@ -639,7 +637,7 @@ public void maybeSetText(ReactTextUpdate reactTextUpdate) {
639
637
}
640
638
641
639
// Update cached spans (in Fabric only).
642
- updateCachedSpannable (false );
640
+ updateCachedSpannable ();
643
641
}
644
642
645
643
/**
@@ -648,8 +646,7 @@ public void maybeSetText(ReactTextUpdate reactTextUpdate) {
648
646
* will adapt to the new text, hence why {@link SpannableStringBuilder#replace} never removes
649
647
* them.
650
648
*/
651
- private void manageSpans (
652
- SpannableStringBuilder spannableStringBuilder , boolean skipAddSpansForMeasurements ) {
649
+ private void manageSpans (SpannableStringBuilder spannableStringBuilder ) {
653
650
Object [] spans = getText ().getSpans (0 , length (), Object .class );
654
651
for (int spanIdx = 0 ; spanIdx < spans .length ; spanIdx ++) {
655
652
Object span = spans [spanIdx ];
@@ -677,13 +674,6 @@ private void manageSpans(
677
674
spannableStringBuilder .setSpan (span , spanStart , spanEnd , spanFlags );
678
675
}
679
676
}
680
-
681
- // In Fabric only, apply necessary styles to entire span
682
- // If the Spannable was constructed from multiple fragments, we don't apply any spans that could
683
- // impact the whole Spannable, because that would override "local" styles per-fragment
684
- if (!skipAddSpansForMeasurements ) {
685
- addSpansForMeasurement (getText ());
686
- }
687
677
}
688
678
689
679
// TODO: Replace with Predicate<T> and lambdas once Java 8 builds in OSS
@@ -785,10 +775,10 @@ private <T> void stripSpansOfKind(
785
775
}
786
776
787
777
/**
788
- * Copy back styles represented as attributes to the underlying span, for later measurement
789
- * outside the ReactEditText.
778
+ * Copy styles represented as attributes to the underlying span, for later measurement or other
779
+ * usage outside the ReactEditText.
790
780
*/
791
- private void restoreStyleEquivalentSpans (SpannableStringBuilder workingText ) {
781
+ private void addSpansFromStyleAttributes (SpannableStringBuilder workingText ) {
792
782
int spanFlags = Spannable .SPAN_INCLUSIVE_INCLUSIVE ;
793
783
794
784
// Set all bits for SPAN_PRIORITY so that this span has the highest possible priority
@@ -844,6 +834,11 @@ private void restoreStyleEquivalentSpans(SpannableStringBuilder workingText) {
844
834
workingText .length (),
845
835
spanFlags );
846
836
}
837
+
838
+ float lineHeight = mTextAttributes .getEffectiveLineHeight ();
839
+ if (!Float .isNaN (lineHeight )) {
840
+ workingText .setSpan (new CustomLineHeightSpan (lineHeight ), 0 , workingText .length (), spanFlags );
841
+ }
847
842
}
848
843
849
844
private static boolean sameTextForSpan (
@@ -862,73 +857,6 @@ private static boolean sameTextForSpan(
862
857
return true ;
863
858
}
864
859
865
- // This is hacked in for Fabric. When we delete non-Fabric code, we might be able to simplify or
866
- // clean this up a bit.
867
- private void addSpansForMeasurement (Spannable spannable ) {
868
- if (!mFabricViewStateManager .hasStateWrapper ()) {
869
- return ;
870
- }
871
-
872
- boolean originalDisableTextDiffing = mDisableTextDiffing ;
873
- mDisableTextDiffing = true ;
874
-
875
- int start = 0 ;
876
- int end = spannable .length ();
877
-
878
- // Remove duplicate spans we might add here
879
- Object [] spans = spannable .getSpans (0 , length (), Object .class );
880
- for (Object span : spans ) {
881
- int spanFlags = spannable .getSpanFlags (span );
882
- boolean isInclusive =
883
- (spanFlags & Spanned .SPAN_INCLUSIVE_INCLUSIVE ) == Spanned .SPAN_INCLUSIVE_INCLUSIVE
884
- || (spanFlags & Spanned .SPAN_INCLUSIVE_EXCLUSIVE ) == Spanned .SPAN_INCLUSIVE_EXCLUSIVE ;
885
- if (isInclusive
886
- && span instanceof ReactSpan
887
- && spannable .getSpanStart (span ) == start
888
- && spannable .getSpanEnd (span ) == end ) {
889
- spannable .removeSpan (span );
890
- }
891
- }
892
-
893
- List <TextLayoutManager .SetSpanOperation > ops = new ArrayList <>();
894
-
895
- if (!Float .isNaN (mTextAttributes .getLetterSpacing ())) {
896
- ops .add (
897
- new TextLayoutManager .SetSpanOperation (
898
- start , end , new CustomLetterSpacingSpan (mTextAttributes .getLetterSpacing ())));
899
- }
900
- ops .add (
901
- new TextLayoutManager .SetSpanOperation (
902
- start , end , new ReactAbsoluteSizeSpan ((int ) mTextAttributes .getEffectiveFontSize ())));
903
- if (mFontStyle != UNSET || mFontWeight != UNSET || mFontFamily != null ) {
904
- ops .add (
905
- new TextLayoutManager .SetSpanOperation (
906
- start ,
907
- end ,
908
- new CustomStyleSpan (
909
- mFontStyle ,
910
- mFontWeight ,
911
- null , // TODO: do we need to support FontFeatureSettings / fontVariant?
912
- mFontFamily ,
913
- getReactContext (ReactEditText .this ).getAssets ())));
914
- }
915
- if (!Float .isNaN (mTextAttributes .getEffectiveLineHeight ())) {
916
- ops .add (
917
- new TextLayoutManager .SetSpanOperation (
918
- start , end , new CustomLineHeightSpan (mTextAttributes .getEffectiveLineHeight ())));
919
- }
920
-
921
- int priority = 0 ;
922
- for (TextLayoutManager .SetSpanOperation op : ops ) {
923
- // Actual order of calling {@code execute} does NOT matter,
924
- // but the {@code priority} DOES matter.
925
- op .execute (spannable , priority );
926
- priority ++;
927
- }
928
-
929
- mDisableTextDiffing = originalDisableTextDiffing ;
930
- }
931
-
932
860
protected boolean showSoftKeyboard () {
933
861
return mInputMethodManager .showSoftInput (this , 0 );
934
862
}
@@ -1215,7 +1143,7 @@ public FabricViewStateManager getFabricViewStateManager() {
1215
1143
* TextLayoutManager.java with some very minor modifications. There's some duplication between
1216
1144
* here and TextLayoutManager, so there might be an opportunity for refactor.
1217
1145
*/
1218
- private void updateCachedSpannable (boolean resetStyles ) {
1146
+ private void updateCachedSpannable () {
1219
1147
// Noops in non-Fabric
1220
1148
if (mFabricViewStateManager == null || !mFabricViewStateManager .hasStateWrapper ()) {
1221
1149
return ;
@@ -1225,12 +1153,6 @@ private void updateCachedSpannable(boolean resetStyles) {
1225
1153
return ;
1226
1154
}
1227
1155
1228
- if (resetStyles ) {
1229
- mIsSettingTextFromCacheUpdate = true ;
1230
- addSpansForMeasurement (getText ());
1231
- mIsSettingTextFromCacheUpdate = false ;
1232
- }
1233
-
1234
1156
Editable currentText = getText ();
1235
1157
boolean haveText = currentText != null && currentText .length () > 0 ;
1236
1158
@@ -1273,7 +1195,6 @@ private void updateCachedSpannable(boolean resetStyles) {
1273
1195
// - android.app.Activity.dispatchKeyEvent (Activity.java:3447)
1274
1196
try {
1275
1197
sb .append (currentText .subSequence (0 , currentText .length ()));
1276
- restoreStyleEquivalentSpans (sb );
1277
1198
} catch (IndexOutOfBoundsException e ) {
1278
1199
ReactSoftExceptionLogger .logSoftException (TAG , e );
1279
1200
}
@@ -1289,11 +1210,9 @@ private void updateCachedSpannable(boolean resetStyles) {
1289
1210
// Measure something so we have correct height, even if there's no string.
1290
1211
sb .append ("I" );
1291
1212
}
1292
-
1293
- // Make sure that all text styles are applied when we're measurable the hint or "blank" text
1294
- addSpansForMeasurement (sb );
1295
1213
}
1296
1214
1215
+ addSpansFromStyleAttributes (sb );
1297
1216
TextLayoutManager .setCachedSpannabledForTag (getId (), sb );
1298
1217
}
1299
1218
@@ -1308,7 +1227,7 @@ void setEventDispatcher(@Nullable EventDispatcher eventDispatcher) {
1308
1227
private class TextWatcherDelegator implements TextWatcher {
1309
1228
@ Override
1310
1229
public void beforeTextChanged (CharSequence s , int start , int count , int after ) {
1311
- if (!mIsSettingTextFromCacheUpdate && ! mIsSettingTextFromJS && mListeners != null ) {
1230
+ if (!mIsSettingTextFromJS && mListeners != null ) {
1312
1231
for (TextWatcher listener : mListeners ) {
1313
1232
listener .beforeTextChanged (s , start , count , after );
1314
1233
}
@@ -1322,23 +1241,20 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {
1322
1241
TAG , "onTextChanged[" + getId () + "]: " + s + " " + start + " " + before + " " + count );
1323
1242
}
1324
1243
1325
- if (!mIsSettingTextFromCacheUpdate ) {
1326
- if (!mIsSettingTextFromJS && mListeners != null ) {
1327
- for (TextWatcher listener : mListeners ) {
1328
- listener .onTextChanged (s , start , before , count );
1329
- }
1244
+ if (!mIsSettingTextFromJS && mListeners != null ) {
1245
+ for (TextWatcher listener : mListeners ) {
1246
+ listener .onTextChanged (s , start , before , count );
1330
1247
}
1331
-
1332
- updateCachedSpannable (
1333
- !mIsSettingTextFromJS && !mIsSettingTextFromState && start == 0 && before == 0 );
1334
1248
}
1335
1249
1250
+ updateCachedSpannable ();
1251
+
1336
1252
onContentSizeChange ();
1337
1253
}
1338
1254
1339
1255
@ Override
1340
1256
public void afterTextChanged (Editable s ) {
1341
- if (!mIsSettingTextFromCacheUpdate && ! mIsSettingTextFromJS && mListeners != null ) {
1257
+ if (!mIsSettingTextFromJS && mListeners != null ) {
1342
1258
for (TextWatcher listener : mListeners ) {
1343
1259
listener .afterTextChanged (s );
1344
1260
}
0 commit comments