Permalink
Browse files

Add <Text> shadow support

Summary:
Add three new TextStylePropTypes for \<Text>
- textShadowOffset
- textShadowRadius
- textShadowColor
Closes #4975

Reviewed By: svcscm

Differential Revision: D2796278

Pulled By: nicklockwood

fb-gh-sync-id: f8c3fa210e664428b029b9fba8eca4a8eb81c08d
  • Loading branch information...
Kudo authored and facebook-github-bot-9 committed Jan 1, 2016
1 parent 718cd79 commit 4972cabaa5f12a1633c74fca1be901d01f16faf9
@@ -365,6 +365,11 @@ var TextExample = React.createClass({
This text contains an inline image <Image source={require('./flux.png')}/>. Neat, huh?
</Text>
</UIExplorerBlock>
+ <UIExplorerBlock title="Text shadow">
+ <Text style={{fontSize: 20, textShadowOffset: {width: 2, height: 2}, textShadowRadius: 1, textShadowColor: '#00cccc'}}>
+ Demo text shadow
+ </Text>
+ </UIExplorerBlock>
</UIExplorerPage>
);
}
@@ -424,6 +424,17 @@ exports.examples = [
</View>
);
},
+}, {
+ title: 'Text shadow',
+ render: function() {
+ return (
+ <View>
+ <Text style={{fontSize: 20, textShadowOffset: {width: 2, height: 2}, textShadowRadius: 1, textShadowColor: '#00cccc'}}>
+ Demo text shadow
+ </Text>
+ </View>
+ );
+ },
}];
var styles = StyleSheet.create({
@@ -46,5 +46,6 @@ ReactNativeStyleAttributes.color = colorAttributes;
ReactNativeStyleAttributes.shadowColor = colorAttributes;
ReactNativeStyleAttributes.textDecorationColor = colorAttributes;
ReactNativeStyleAttributes.tintColor = colorAttributes;
+ReactNativeStyleAttributes.textShadowColor = colorAttributes;
module.exports = ReactNativeStyleAttributes;
@@ -33,6 +33,9 @@ extern NSString *const RCTReactTagAttributeName;
@property (nonatomic, assign) CGFloat fontSizeMultiplier;
@property (nonatomic, assign) BOOL allowFontScaling;
@property (nonatomic, assign) CGFloat opacity;
+@property (nonatomic, assign) CGSize textShadowOffset;
+@property (nonatomic, assign) CGFloat textShadowRadius;
+@property (nonatomic, strong) UIColor *textShadowColor;
- (void)recomputeText;
@@ -305,22 +305,31 @@ - (void)_setParagraphStyleOnAttributedString:(NSMutableAttributedString *)attrib
}
// Text decoration
- if(_textDecorationLine == RCTTextDecorationLineTypeUnderline ||
- _textDecorationLine == RCTTextDecorationLineTypeUnderlineStrikethrough) {
+ if (_textDecorationLine == RCTTextDecorationLineTypeUnderline ||
+ _textDecorationLine == RCTTextDecorationLineTypeUnderlineStrikethrough) {
[self _addAttribute:NSUnderlineStyleAttributeName withValue:@(_textDecorationStyle)
toAttributedString:attributedString];
}
- if(_textDecorationLine == RCTTextDecorationLineTypeStrikethrough ||
- _textDecorationLine == RCTTextDecorationLineTypeUnderlineStrikethrough){
+ if (_textDecorationLine == RCTTextDecorationLineTypeStrikethrough ||
+ _textDecorationLine == RCTTextDecorationLineTypeUnderlineStrikethrough){
[self _addAttribute:NSStrikethroughStyleAttributeName withValue:@(_textDecorationStyle)
toAttributedString:attributedString];
}
- if(_textDecorationColor) {
+ if (_textDecorationColor) {
[self _addAttribute:NSStrikethroughColorAttributeName withValue:_textDecorationColor
toAttributedString:attributedString];
[self _addAttribute:NSUnderlineColorAttributeName withValue:_textDecorationColor
toAttributedString:attributedString];
}
+
+ // Text shadow
+ if (!CGSizeEqualToSize(_textShadowOffset, CGSizeZero)) {
+ NSShadow *shadow = [NSShadow new];
+ shadow.shadowOffset = _textShadowOffset;
+ shadow.shadowBlurRadius = _textShadowRadius;
+ shadow.shadowColor = _textShadowColor;
+ [self _addAttribute:NSShadowAttributeName withValue:shadow toAttributedString:attributedString];
+ }
}
- (void)fillCSSNode:(css_node_t *)node
@@ -371,6 +380,9 @@ - (void)set##setProp:(type)value; \
RCT_TEXT_PROPERTY(TextDecorationStyle, _textDecorationStyle, NSUnderlineStyle);
RCT_TEXT_PROPERTY(WritingDirection, _writingDirection, NSWritingDirection)
RCT_TEXT_PROPERTY(Opacity, _opacity, CGFloat)
+RCT_TEXT_PROPERTY(TextShadowOffset, _textShadowOffset, CGSize);
+RCT_TEXT_PROPERTY(TextShadowRadius, _textShadowRadius, CGFloat);
+RCT_TEXT_PROPERTY(TextShadowColor, _textShadowColor, UIColor *);
- (void)setAllowFontScaling:(BOOL)allowFontScaling
{
@@ -59,6 +59,9 @@ - (RCTShadowView *)shadowView
RCT_EXPORT_SHADOW_PROPERTY(writingDirection, NSWritingDirection)
RCT_EXPORT_SHADOW_PROPERTY(allowFontScaling, BOOL)
RCT_EXPORT_SHADOW_PROPERTY(opacity, CGFloat)
+RCT_EXPORT_SHADOW_PROPERTY(textShadowOffset, CGSize)
+RCT_EXPORT_SHADOW_PROPERTY(textShadowRadius, CGFloat)
+RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, UIColor)
- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(NSDictionary<NSNumber *, RCTShadowView *> *)shadowViewRegistry
{
@@ -30,6 +30,11 @@ var TextStylePropTypes = Object.assign(Object.create(ViewStylePropTypes), {
['normal' /*default*/, 'bold',
'100', '200', '300', '400', '500', '600', '700', '800', '900']
),
+ textShadowOffset: ReactPropTypes.shape(
+ {width: ReactPropTypes.number, height: ReactPropTypes.number}
+ ),
+ textShadowRadius: ReactPropTypes.number,
+ textShadowColor: ColorPropType,
/**
* @platform ios
*/
@@ -32,6 +32,7 @@
import com.facebook.csslayout.CSSNode;
import com.facebook.csslayout.MeasureOutput;
import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.common.annotations.VisibleForTesting;
import com.facebook.react.uimanager.IllegalViewOperationException;
import com.facebook.react.uimanager.LayoutShadowNode;
@@ -63,6 +64,11 @@
@VisibleForTesting
public static final String PROP_TEXT = "text";
+ public static final String PROP_SHADOW_OFFSET = "textShadowOffset";
+ public static final String PROP_SHADOW_RADIUS = "textShadowRadius";
+ public static final String PROP_SHADOW_COLOR = "textShadowColor";
+ public static final int DEFAULT_TEXT_SHADOW_COLOR = 0x55000000;
+
private static final TextPaint sTextPaintInstance = new TextPaint();
static {
@@ -114,8 +120,7 @@ private static final void buildSpannedFromTextCSSNode(
ops.add(new SetSpanOperation(start, end, new ForegroundColorSpan(textCSSNode.mColor)));
}
if (textCSSNode.mIsBackgroundColorSet) {
- ops.add(
- new SetSpanOperation(
+ ops.add(new SetSpanOperation(
start,
end,
new BackgroundColorSpan(textCSSNode.mBackgroundColor)));
@@ -135,6 +140,16 @@ private static final void buildSpannedFromTextCSSNode(
textCSSNode.mFontFamily,
textCSSNode.getThemedContext().getAssets())));
}
+ if (textCSSNode.mTextShadowOffsetDx != 0 || textCSSNode.mTextShadowOffsetDy != 0) {
+ ops.add(new SetSpanOperation(
+ start,
+ end,
+ new ShadowStyleSpan(
+ textCSSNode.mTextShadowOffsetDx,
+ textCSSNode.mTextShadowOffsetDy,
+ textCSSNode.mTextShadowRadius,
+ textCSSNode.mTextShadowColor)));
+ }
ops.add(new SetSpanOperation(start, end, new ReactTagSpan(textCSSNode.getReactTag())));
}
}
@@ -279,6 +294,11 @@ private static int parseNumericFontWeight(String fontWeightString) {
protected int mNumberOfLines = UNSET;
protected int mFontSize = UNSET;
+ private float mTextShadowOffsetDx = 0;
+ private float mTextShadowOffsetDy = 0;
+ private float mTextShadowRadius = 1;
+ private int mTextShadowColor = DEFAULT_TEXT_SHADOW_COLOR;
+
/**
* mFontStyle can be {@link Typeface#NORMAL} or {@link Typeface#ITALIC}.
* mFontWeight can be {@link Typeface#NORMAL} or {@link Typeface#BOLD}.
@@ -413,6 +433,34 @@ public void setFontStyle(@Nullable String fontStyleString) {
}
}
+ @ReactProp(name = PROP_SHADOW_OFFSET)
+ public void setTextShadowOffset(ReadableMap offsetMap) {
+ if (offsetMap == null) {
+ mTextShadowOffsetDx = 0;
+ mTextShadowOffsetDy = 0;
+ } else {
+ mTextShadowOffsetDx = PixelUtil.toPixelFromDIP(offsetMap.getDouble("width"));
+ mTextShadowOffsetDy = PixelUtil.toPixelFromDIP(offsetMap.getDouble("height"));
+ }
+ markUpdated();
+ }
+
+ @ReactProp(name = PROP_SHADOW_RADIUS, defaultInt = 1)
+ public void setTextShadowRadius(float textShadowRadius) {
+ if (textShadowRadius != mTextShadowRadius) {
+ mTextShadowRadius = textShadowRadius;
+ markUpdated();
+ }
+ }
+
+ @ReactProp(name = PROP_SHADOW_COLOR, defaultInt = DEFAULT_TEXT_SHADOW_COLOR, customType = "Color")
+ public void setTextShadowColor(int textShadowColor) {
+ if (textShadowColor != mTextShadowColor) {
+ mTextShadowColor = textShadowColor;
+ markUpdated();
+ }
+ }
+
@Override
public boolean isVirtualAnchor() {
return !mIsVirtual;
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+package com.facebook.react.views.text;
+
+
+import android.text.TextPaint;
+import android.text.style.CharacterStyle;
+
+public class ShadowStyleSpan extends CharacterStyle {
+ private final float mDx, mDy, mRadius;
+ private final int mColor;
+
+ public ShadowStyleSpan(float dx, float dy, float radius, int color) {
+ mDx = dx;
+ mDy = dy;
+ mRadius = radius;
+ mColor = color;
+ }
+
+ @Override
+ public void updateDrawState(TextPaint textPaint) {
+ textPaint.setShadowLayer(mRadius, mDx, mDy, mColor);
+ }
+}

0 comments on commit 4972cab

Please sign in to comment.