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
}
@@ -1210,7 +1138,7 @@ public FabricViewStateManager getFabricViewStateManager() {
1210
1138
* TextLayoutManager.java with some very minor modifications. There's some duplication between
1211
1139
* here and TextLayoutManager, so there might be an opportunity for refactor.
1212
1140
*/
1213
- private void updateCachedSpannable (boolean resetStyles ) {
1141
+ private void updateCachedSpannable () {
1214
1142
// Noops in non-Fabric
1215
1143
if (mFabricViewStateManager == null || !mFabricViewStateManager .hasStateWrapper ()) {
1216
1144
return ;
@@ -1220,12 +1148,6 @@ private void updateCachedSpannable(boolean resetStyles) {
1220
1148
return ;
1221
1149
}
1222
1150
1223
- if (resetStyles ) {
1224
- mIsSettingTextFromCacheUpdate = true ;
1225
- addSpansForMeasurement (getText ());
1226
- mIsSettingTextFromCacheUpdate = false ;
1227
- }
1228
-
1229
1151
Editable currentText = getText ();
1230
1152
boolean haveText = currentText != null && currentText .length () > 0 ;
1231
1153
@@ -1268,7 +1190,6 @@ private void updateCachedSpannable(boolean resetStyles) {
1268
1190
// - android.app.Activity.dispatchKeyEvent (Activity.java:3447)
1269
1191
try {
1270
1192
sb .append (currentText .subSequence (0 , currentText .length ()));
1271
- restoreStyleEquivalentSpans (sb );
1272
1193
} catch (IndexOutOfBoundsException e ) {
1273
1194
ReactSoftExceptionLogger .logSoftException (TAG , e );
1274
1195
}
@@ -1284,11 +1205,9 @@ private void updateCachedSpannable(boolean resetStyles) {
1284
1205
// Measure something so we have correct height, even if there's no string.
1285
1206
sb .append ("I" );
1286
1207
}
1287
-
1288
- // Make sure that all text styles are applied when we're measurable the hint or "blank" text
1289
- addSpansForMeasurement (sb );
1290
1208
}
1291
1209
1210
+ addSpansFromStyleAttributes (sb );
1292
1211
TextLayoutManager .setCachedSpannabledForTag (getId (), sb );
1293
1212
}
1294
1213
@@ -1303,7 +1222,7 @@ void setEventDispatcher(@Nullable EventDispatcher eventDispatcher) {
1303
1222
private class TextWatcherDelegator implements TextWatcher {
1304
1223
@ Override
1305
1224
public void beforeTextChanged (CharSequence s , int start , int count , int after ) {
1306
- if (!mIsSettingTextFromCacheUpdate && ! mIsSettingTextFromJS && mListeners != null ) {
1225
+ if (!mIsSettingTextFromJS && mListeners != null ) {
1307
1226
for (TextWatcher listener : mListeners ) {
1308
1227
listener .beforeTextChanged (s , start , count , after );
1309
1228
}
@@ -1317,23 +1236,20 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {
1317
1236
TAG , "onTextChanged[" + getId () + "]: " + s + " " + start + " " + before + " " + count );
1318
1237
}
1319
1238
1320
- if (!mIsSettingTextFromCacheUpdate ) {
1321
- if (!mIsSettingTextFromJS && mListeners != null ) {
1322
- for (TextWatcher listener : mListeners ) {
1323
- listener .onTextChanged (s , start , before , count );
1324
- }
1239
+ if (!mIsSettingTextFromJS && mListeners != null ) {
1240
+ for (TextWatcher listener : mListeners ) {
1241
+ listener .onTextChanged (s , start , before , count );
1325
1242
}
1326
-
1327
- updateCachedSpannable (
1328
- !mIsSettingTextFromJS && !mIsSettingTextFromState && start == 0 && before == 0 );
1329
1243
}
1330
1244
1245
+ updateCachedSpannable ();
1246
+
1331
1247
onContentSizeChange ();
1332
1248
}
1333
1249
1334
1250
@ Override
1335
1251
public void afterTextChanged (Editable s ) {
1336
- if (!mIsSettingTextFromCacheUpdate && ! mIsSettingTextFromJS && mListeners != null ) {
1252
+ if (!mIsSettingTextFromJS && mListeners != null ) {
1337
1253
for (TextWatcher listener : mListeners ) {
1338
1254
listener .afterTextChanged (s );
1339
1255
}
0 commit comments