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 5c4feaf02f9e10..10b9d4d7d3b1dd 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java @@ -73,6 +73,7 @@ public class ViewProps { public static final String FONT_STYLE = "fontStyle"; public static final String FONT_FAMILY = "fontFamily"; public static final String LINE_HEIGHT = "lineHeight"; + public static final String LETTER_SPACING = "letterSpacing"; public static final String NEEDS_OFFSCREEN_ALPHA_COMPOSITING = "needsOffscreenAlphaCompositing"; public static final String NUMBER_OF_LINES = "numberOfLines"; public static final String ELLIPSIZE_MODE = "ellipsizeMode"; 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 8df4adcbdd5226..d784b63c798746 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 @@ -331,6 +331,7 @@ private static int parseNumericFontWeight(String fontWeightString) { } private float mLineHeight = Float.NaN; + private float mLetterSpacing = Float.NaN; private boolean mIsColorSet = false; private boolean mAllowFontScaling = true; private int mColor; @@ -390,6 +391,14 @@ public ReactTextShadowNode() { } } + public float getLetterSpacing() { + return mLetterSpacing; + } + + public int getFontSize() { + return mFontSize; + } + // Returns a line height which takes into account the requested line height // and the height of the inline images. public float getEffectiveLineHeight() { @@ -464,6 +473,12 @@ public void setAllowFontScaling(boolean allowFontScaling) { } } + @ReactProp(name = ViewProps.LETTER_SPACING, defaultFloat = UNSET) + public void setLetterSpacing(float letterSpacing) { + mLetterSpacing = letterSpacing == UNSET ? Float.NaN : letterSpacing; + markUpdated(); + } + @ReactProp(name = ViewProps.TEXT_ALIGN) public void setTextAlign(@Nullable String textAlign) { if (textAlign == null || "auto".equals(textAlign)) { @@ -653,6 +668,8 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) { getPadding(Spacing.TOP), getPadding(Spacing.END), getPadding(Spacing.BOTTOM), + getLetterSpacing(), + getFontSize(), getTextAlign(), mTextBreakStrategy ); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java index 9f67aec6180dee..aedc2a65a9d74c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java @@ -26,6 +26,8 @@ public class ReactTextUpdate { private final float mPaddingTop; private final float mPaddingRight; private final float mPaddingBottom; + private final float mLetterSpacing; + private final int mFontSize; private final int mTextAlign; private final int mTextBreakStrategy; @@ -62,6 +64,8 @@ public ReactTextUpdate( float paddingTop, float paddingEnd, float paddingBottom, + float letterSpacing, + int fontSize, int textAlign, int textBreakStrategy) { mText = text; @@ -71,6 +75,8 @@ public ReactTextUpdate( mPaddingTop = paddingTop; mPaddingRight = paddingEnd; mPaddingBottom = paddingBottom; + mLetterSpacing = letterSpacing; + mFontSize = fontSize; mTextAlign = textAlign; mTextBreakStrategy = textBreakStrategy; } @@ -103,6 +109,14 @@ public float getPaddingBottom() { return mPaddingBottom; } + public float getLetterSpacing() { + return mLetterSpacing; + } + + public int getFontSize() { + return mFontSize; + } + public int getTextAlign() { return mTextAlign; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java index 3d5d9668bd8106..ac715a4cc3cb9b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java @@ -23,6 +23,8 @@ import android.view.ViewGroup; import android.widget.TextView; +import com.facebook.csslayout.FloatUtil; +import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.ReactCompoundView; import com.facebook.react.uimanager.ViewDefaults; import com.facebook.react.views.view.ReactViewBackgroundDrawable; @@ -37,6 +39,7 @@ public class ReactTextView extends TextView implements ReactCompoundView { private int mDefaultGravityVertical; private boolean mTextIsSelectable; private float mLineHeight = Float.NaN; + private float mLetterSpacing = Float.NaN; private int mTextAlign = Gravity.NO_GRAVITY; private int mNumberOfLines = ViewDefaults.NUMBER_OF_LINES; private TextUtils.TruncateAt mEllipsizeLocation = TextUtils.TruncateAt.END; @@ -65,6 +68,21 @@ public void setText(ReactTextUpdate update) { (int) Math.floor(update.getPaddingRight()), (int) Math.floor(update.getPaddingBottom())); + // API 21+: https://developer.android.com/reference/android/widget/TextView.html#setLetterSpacing(float) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + float nextLetterSpacing = update.getLetterSpacing(); + int fontSize = update.getFontSize(); + if (!FloatUtil.floatsEqual(mLetterSpacing, nextLetterSpacing)) { + mLetterSpacing = nextLetterSpacing; + if(Float.isNaN(mLetterSpacing)) { + setLetterSpacing((float)0.0); + } else { + //calculate EM from proper font pixels + setLetterSpacing(1+(mLetterSpacing-PixelUtil.toDIPFromPixel(fontSize))/PixelUtil.toDIPFromPixel(fontSize)); + } + } + } + int nextTextAlign = update.getTextAlign(); if (mTextAlign != nextTextAlign) { mTextAlign = nextTextAlign; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java index 409cf13e4ec013..2259cdb1322e33 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java @@ -103,6 +103,11 @@ public long measure( (int) Math.floor(getPadding(Spacing.END)), (int) Math.floor(getPadding(Spacing.BOTTOM))); + // API 21+: https://developer.android.com/reference/android/widget/TextView.html#setLetterSpacing(float) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + editText.setLetterSpacing(getLetterSpacing()); + } + if (mNumberOfLines != UNSET) { editText.setLines(mNumberOfLines); } @@ -176,6 +181,8 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) { getPadding(Spacing.TOP), getPadding(Spacing.END), getPadding(Spacing.BOTTOM), + getLetterSpacing(), + getFontSize(), mTextAlign, mTextBreakStrategy );