diff --git a/Examples/UIExplorer/TextExample.android.js b/Examples/UIExplorer/TextExample.android.js index 0d7efa1d5fd72b..4d1f61b4fc165a 100644 --- a/Examples/UIExplorer/TextExample.android.js +++ b/Examples/UIExplorer/TextExample.android.js @@ -215,6 +215,23 @@ var TextExample = React.createClass({ Move fast and be bold + + + Solid underline + + + None textDecoration + + + Solid line-through + + + Both underline and line-through + + + Mixed text with underline and line-through text nodes + + console.log('1st')}> (Normal text, diff --git a/Libraries/Text/TextStylePropTypes.js b/Libraries/Text/TextStylePropTypes.js index 9c4668174e4f8e..2f67fb73e8e7f0 100644 --- a/Libraries/Text/TextStylePropTypes.js +++ b/Libraries/Text/TextStylePropTypes.js @@ -52,9 +52,6 @@ var TextStylePropTypes = Object.assign(Object.create(ViewStylePropTypes), { textAlignVertical: ReactPropTypes.oneOf( ['auto' /*default*/, 'top', 'bottom', 'center'] ), - /** - * @platform ios - */ textDecorationLine: ReactPropTypes.oneOf( ['none' /*default*/, 'underline', 'line-through', 'underline line-through'] ), diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java index 3cef8895ac77c9..38160e477afa54 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java @@ -71,6 +71,7 @@ public class ViewProps { public static final String RESIZE_MODE = "resizeMode"; public static final String TEXT_ALIGN = "textAlign"; public static final String TEXT_ALIGN_VERTICAL = "textAlignVertical"; + public static final String TEXT_DECORATION_LINE = "textDecorationLine"; public static final String BORDER_WIDTH = "borderWidth"; public static final String BORDER_LEFT_WIDTH = "borderLeftWidth"; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java index 36996a1f8f5792..657695284b979a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java @@ -25,6 +25,8 @@ import android.text.style.AbsoluteSizeSpan; import android.text.style.BackgroundColorSpan; import android.text.style.ForegroundColorSpan; +import android.text.style.StrikethroughSpan; +import android.text.style.UnderlineSpan; import android.widget.TextView; import com.facebook.csslayout.CSSConstants; @@ -146,6 +148,12 @@ private static void buildSpannedFromTextCSSNode( textCSSNode.mFontFamily, textCSSNode.getThemedContext().getAssets()))); } + if (textCSSNode.mIsUnderlineTextDecorationSet) { + ops.add(new SetSpanOperation(start, end, new UnderlineSpan())); + } + if (textCSSNode.mIsLineThroughTextDecorationSet) { + ops.add(new SetSpanOperation(start, end, new StrikethroughSpan())); + } if (textCSSNode.mTextShadowOffsetDx != 0 || textCSSNode.mTextShadowOffsetDy != 0) { ops.add(new SetSpanOperation( start, @@ -287,6 +295,9 @@ private static int parseNumericFontWeight(String fontWeightString) { private float mTextShadowRadius = 1; private int mTextShadowColor = DEFAULT_TEXT_SHADOW_COLOR; + private boolean mIsUnderlineTextDecorationSet = false; + private boolean mIsLineThroughTextDecorationSet = false; + /** * mFontStyle can be {@link Typeface#NORMAL} or {@link Typeface#ITALIC}. * mFontWeight can be {@link Typeface#NORMAL} or {@link Typeface#BOLD}. @@ -428,6 +439,22 @@ public void setFontStyle(@Nullable String fontStyleString) { } } + @ReactProp(name = ViewProps.TEXT_DECORATION_LINE) + public void setTextDecorationLine(@Nullable String textDecorationLineString) { + mIsUnderlineTextDecorationSet = false; + mIsLineThroughTextDecorationSet = false; + if (textDecorationLineString != null) { + for (String textDecorationLineSubString : textDecorationLineString.split(" ")) { + if ("underline".equals(textDecorationLineSubString)) { + mIsUnderlineTextDecorationSet = true; + } else if ("line-through".equals(textDecorationLineSubString)) { + mIsLineThroughTextDecorationSet = true; + } + } + } + markUpdated(); + } + @ReactProp(name = PROP_SHADOW_OFFSET) public void setTextShadowOffset(ReadableMap offsetMap) { if (offsetMap == null) { diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java index 68734c4a502aec..257f77a89bb19e 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java @@ -22,6 +22,8 @@ import android.text.Spanned; import android.text.TextUtils; import android.text.style.AbsoluteSizeSpan; +import android.text.style.StrikethroughSpan; +import android.text.style.UnderlineSpan; import android.util.DisplayMetrics; import android.view.Choreographer; import android.widget.TextView; @@ -279,6 +281,60 @@ public void testFontFamilyBoldItalicStyleApplied() { assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isNotZero(); } + @Test + public void testTextDecorationLineUnderlineApplied() { + UIManagerModule uiManager = getUIManagerModule(); + + ReactRootView rootView = createText( + uiManager, + JavaOnlyMap.of(ViewProps.TEXT_DECORATION_LINE, "underline"), + JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text")); + + TextView textView = (TextView) rootView.getChildAt(0); + Spanned text = (Spanned) textView.getText(); + UnderlineSpan underlineSpan = getSingleSpan(textView, UnderlineSpan.class); + StrikethroughSpan[] strikeThroughSpans = + text.getSpans(0, text.length(), StrikethroughSpan.class); + assertThat(underlineSpan instanceof UnderlineSpan).isTrue(); + assertThat(strikeThroughSpans).hasSize(0); + } + + @Test + public void testTextDecorationLineLineThroughApplied() { + UIManagerModule uiManager = getUIManagerModule(); + + ReactRootView rootView = createText( + uiManager, + JavaOnlyMap.of(ViewProps.TEXT_DECORATION_LINE, "line-through"), + JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text")); + + TextView textView = (TextView) rootView.getChildAt(0); + Spanned text = (Spanned) textView.getText(); + UnderlineSpan[] underlineSpans = + text.getSpans(0, text.length(), UnderlineSpan.class); + StrikethroughSpan strikeThroughSpan = + getSingleSpan(textView, StrikethroughSpan.class); + assertThat(underlineSpans).hasSize(0); + assertThat(strikeThroughSpan instanceof StrikethroughSpan).isTrue(); + } + + @Test + public void testTextDecorationLineUnderlineLineThroughApplied() { + UIManagerModule uiManager = getUIManagerModule(); + + ReactRootView rootView = createText( + uiManager, + JavaOnlyMap.of(ViewProps.TEXT_DECORATION_LINE, "underline line-through"), + JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text")); + + UnderlineSpan underlineSpan = + getSingleSpan((TextView) rootView.getChildAt(0), UnderlineSpan.class); + StrikethroughSpan strikeThroughSpan = + getSingleSpan((TextView) rootView.getChildAt(0), StrikethroughSpan.class); + assertThat(underlineSpan instanceof UnderlineSpan).isTrue(); + assertThat(strikeThroughSpan instanceof StrikethroughSpan).isTrue(); + } + @Test public void testBackgroundColorStyleApplied() { UIManagerModule uiManager = getUIManagerModule();