diff --git a/Examples/UIExplorer/TextInputExample.android.js b/Examples/UIExplorer/TextInputExample.android.js index b70f2d933..5ae1079f0 100644 --- a/Examples/UIExplorer/TextInputExample.android.js +++ b/Examples/UIExplorer/TextInputExample.android.js @@ -91,6 +91,60 @@ class RewriteExample extends React.Component { } } +class TokenizedTextExample extends React.Component { + constructor(props) { + super(props); + this.state = {text: 'Hello #World'}; + } + render() { + + //define delimiter + let delimiter = /\s+/; + + //split string + let _text = this.state.text; + let token, index, parts = []; + while (_text) { + delimiter.lastIndex = 0; + token = delimiter.exec(_text); + if (token === null) { + break; + } + index = token.index; + if (token[0].length === 0) { + index = 1; + } + parts.push(_text.substr(0, index)); + parts.push(token[0]); + index = index + token[0].length; + _text = _text.slice(index); + } + parts.push(_text); + + //highlight hashtags + parts = parts.map((text) => { + if (/^#/.test(text)) { + return {text}; + } else { + return text; + } + }); + + return ( + + { + this.setState({text}); + }}> + {parts} + + + ); + } +} + var styles = StyleSheet.create({ multiline: { height: 60, @@ -109,6 +163,10 @@ var styles = StyleSheet.create({ singleLineWithHeightTextInput: { height: 30, }, + hashtag: { + color: 'blue', + fontWeight: 'bold', + }, }); exports.title = ''; @@ -322,4 +380,10 @@ exports.examples = [ ); } }, + { + title: 'Attributed text', + render: function() { + return ; + } + }, ]; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java index 79a67f864..4c5f8011c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java @@ -20,12 +20,17 @@ import android.text.InputType; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextWatcher; +import android.text.style.AbsoluteSizeSpan; +import android.text.style.BackgroundColorSpan; +import android.text.style.ForegroundColorSpan; import android.view.Gravity; import android.view.KeyEvent; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import com.facebook.infer.annotation.Assertions; +import com.facebook.react.views.text.CustomStyleSpan; +import com.facebook.react.views.text.ReactTagSpan; /** * A wrapper around the EditText that lets us better control what happens when an EditText gets @@ -204,6 +209,15 @@ public class ReactEditText extends EditText { private void manageSpans(SpannableStringBuilder spannableStringBuilder) { Object[] spans = getText().getSpans(0, length(), Object.class); for (int spanIdx = 0; spanIdx < spans.length; spanIdx++) { + // Remove all styling spans we might have previously set + if (ForegroundColorSpan.class.isInstance(spans[spanIdx]) || + BackgroundColorSpan.class.isInstance(spans[spanIdx]) || + AbsoluteSizeSpan.class.isInstance(spans[spanIdx]) || + CustomStyleSpan.class.isInstance(spans[spanIdx]) || + ReactTagSpan.class.isInstance(spans[spanIdx])) { + getText().removeSpan(spans[spanIdx]); + } + if ((getText().getSpanFlags(spans[spanIdx]) & Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) != Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) { continue; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextChangedEvent.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextChangedEvent.java index f7363441b..268b5c465 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextChangedEvent.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextChangedEvent.java @@ -16,8 +16,9 @@ import com.facebook.react.uimanager.events.RCTEventEmitter; /** * Event emitted by EditText native view when text changes. + * VisibleForTesting from {@link TextInputEventsTestCase}. */ -/* package */ class ReactTextChangedEvent extends Event { +public class ReactTextChangedEvent extends Event { public static final String EVENT_NAME = "topChange"; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputEvent.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputEvent.java index f2cbc8b91..3d8f4ccbb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputEvent.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputEvent.java @@ -16,8 +16,9 @@ import com.facebook.react.uimanager.events.RCTEventEmitter; /** * Event emitted by EditText native view when text changes. + * VisibleForTesting from {@link TextInputEventsTestCase}. */ -/* package */ class ReactTextInputEvent extends Event { +public class ReactTextInputEvent extends Event { public static final String EVENT_NAME = "topTextInput";