Change the textalign setter to support RTL

Summary: Change the textalign setter to support RTL. In order to support text alignment according to layout style, move the textalign setter bridge function from ReactTextViewManager.java to ReactTextShadowNode.java and calculate it correctly on RCTTextUpdate.

Reviewed By: dmmiller

Differential Revision: D3597494

fbshipit-source-id: e5ca17b99b4233cc49a447a34175473e339ff53d
This commit is contained in:
Mengjue Wang 2016-07-26 12:09:29 -07:00 committed by Facebook Github Bot 6
parent ee89ffcb17
commit 54a4450309
5 changed files with 75 additions and 28 deletions

View File

@ -27,13 +27,16 @@ import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.StrikethroughSpan;
import android.text.style.UnderlineSpan;
import android.view.Gravity;
import android.widget.TextView;
import com.facebook.csslayout.CSSDirection;
import com.facebook.csslayout.CSSConstants;
import com.facebook.csslayout.CSSMeasureMode;
import com.facebook.csslayout.CSSNode;
import com.facebook.csslayout.MeasureOutput;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.common.annotations.VisibleForTesting;
import com.facebook.react.uimanager.IllegalViewOperationException;
@ -288,8 +291,8 @@ public class ReactTextShadowNode extends LayoutShadowNode {
/**
* Return -1 if the input string is not a valid numeric fontWeight (100, 200, ..., 900), otherwise
* return the weight.
*
* This code is duplicated in ReactTextInputManager
*
* This code is duplicated in ReactTextInputManager
* TODO: Factor into a common place they can both use
*/
private static int parseNumericFontWeight(String fontWeightString) {
@ -307,6 +310,7 @@ public class ReactTextShadowNode extends LayoutShadowNode {
protected int mNumberOfLines = UNSET;
protected int mFontSize = UNSET;
protected int mTextAlign = UNSET;
private float mTextShadowOffsetDx = 0;
private float mTextShadowOffsetDy = 0;
@ -364,6 +368,19 @@ public class ReactTextShadowNode extends LayoutShadowNode {
return useInlineViewHeight ? mHeightOfTallestInlineImage : mLineHeight;
}
// Return text alignment according to LTR or RTL style
private int getTextAlign() {
int textAlign = mTextAlign;
if (getLayoutDirection() == CSSDirection.RTL) {
if (textAlign == Gravity.RIGHT) {
textAlign = Gravity.LEFT;
} else if (textAlign == Gravity.LEFT) {
textAlign = Gravity.RIGHT;
}
}
return textAlign;
}
@Override
public void onBeforeLayout() {
if (mIsVirtual) {
@ -400,6 +417,25 @@ public class ReactTextShadowNode extends LayoutShadowNode {
markUpdated();
}
@ReactProp(name = ViewProps.TEXT_ALIGN)
public void setTextAlign(@Nullable String textAlign) {
if (textAlign == null || "auto".equals(textAlign)) {
mTextAlign = Gravity.NO_GRAVITY;
} else if ("left".equals(textAlign)) {
mTextAlign = Gravity.LEFT;
} else if ("right".equals(textAlign)) {
mTextAlign = Gravity.RIGHT;
} else if ("center".equals(textAlign)) {
mTextAlign = Gravity.CENTER_HORIZONTAL;
} else if ("justify".equals(textAlign)) {
// Fallback gracefully for cross-platform compat instead of error
mTextAlign = Gravity.LEFT;
} else {
throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign);
}
markUpdated();
}
@ReactProp(name = ViewProps.FONT_SIZE, defaultFloat = UNSET)
public void setFontSize(float fontSize) {
if (fontSize != UNSET) {
@ -429,15 +465,15 @@ public class ReactTextShadowNode extends LayoutShadowNode {
markUpdated();
}
}
@ReactProp(name = ViewProps.FONT_FAMILY)
public void setFontFamily(@Nullable String fontFamily) {
mFontFamily = fontFamily;
markUpdated();
}
/**
/* This code is duplicated in ReactTextInputManager
/* This code is duplicated in ReactTextInputManager
/* TODO: Factor into a common place they can both use
*/
@ReactProp(name = ViewProps.FONT_WEIGHT)
@ -456,9 +492,9 @@ public class ReactTextShadowNode extends LayoutShadowNode {
markUpdated();
}
}
/**
/* This code is duplicated in ReactTextInputManager
/* This code is duplicated in ReactTextInputManager
/* TODO: Factor into a common place they can both use
*/
@ReactProp(name = ViewProps.FONT_STYLE)
@ -546,7 +582,14 @@ public class ReactTextShadowNode extends LayoutShadowNode {
super.onCollectExtraUpdates(uiViewOperationQueue);
if (mPreparedSpannableText != null) {
ReactTextUpdate reactTextUpdate =
new ReactTextUpdate(mPreparedSpannableText, UNSET, mContainsImages, getPadding(), getEffectiveLineHeight());
new ReactTextUpdate(
mPreparedSpannableText,
UNSET,
mContainsImages,
getPadding(),
getEffectiveLineHeight(),
getTextAlign()
);
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}

View File

@ -10,6 +10,7 @@
package com.facebook.react.views.text;
import android.text.Spannable;
import android.view.Gravity;
import com.facebook.csslayout.Spacing;
@ -28,13 +29,15 @@ public class ReactTextUpdate {
private final float mPaddingRight;
private final float mPaddingBottom;
private final float mLineHeight;
private final int mTextAlign;
public ReactTextUpdate(
Spannable text,
int jsEventCounter,
boolean containsImages,
Spacing padding,
float lineHeight) {
float lineHeight,
int textAlign) {
mText = text;
mJsEventCounter = jsEventCounter;
mContainsImages = containsImages;
@ -43,6 +46,7 @@ public class ReactTextUpdate {
mPaddingRight = padding.get(Spacing.RIGHT);
mPaddingBottom = padding.get(Spacing.BOTTOM);
mLineHeight = lineHeight;
mTextAlign = textAlign;
}
public Spannable getText() {
@ -76,4 +80,8 @@ public class ReactTextUpdate {
public float getLineHeight() {
return mLineHeight;
}
public int getTextAlign() {
return mTextAlign;
}
}

View File

@ -30,6 +30,7 @@ public class ReactTextView extends TextView implements ReactCompoundView {
private int mDefaultGravityVertical;
private boolean mTextIsSelectable;
private float mLineHeight = Float.NaN;
private int mTextAlign = Gravity.NO_GRAVITY;
public ReactTextView(Context context) {
super(context);
@ -62,6 +63,12 @@ public class ReactTextView extends TextView implements ReactCompoundView {
setLineSpacing(mLineHeight, 0);
}
}
int nextTextAlign = update.getTextAlign();
if (mTextAlign != nextTextAlign) {
mTextAlign = nextTextAlign;
}
setGravityHorizontal(mTextAlign);
}
@Override

View File

@ -55,24 +55,6 @@ public class ReactTextViewManager extends BaseViewManager<ReactTextView, ReactTe
view.setEllipsize(TextUtils.TruncateAt.END);
}
@ReactProp(name = ViewProps.TEXT_ALIGN)
public void setTextAlign(ReactTextView view, @Nullable String textAlign) {
if (textAlign == null || "auto".equals(textAlign)) {
view.setGravityHorizontal(Gravity.NO_GRAVITY);
} else if ("left".equals(textAlign)) {
view.setGravityHorizontal(Gravity.LEFT);
} else if ("right".equals(textAlign)) {
view.setGravityHorizontal(Gravity.RIGHT);
} else if ("center".equals(textAlign)) {
view.setGravityHorizontal(Gravity.CENTER_HORIZONTAL);
} else if ("justify".equals(textAlign)) {
// Fallback gracefully for cross-platform compat instead of error
view.setGravityHorizontal(Gravity.LEFT);
} else {
throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign);
}
}
@ReactProp(name = ViewProps.LINE_BREAK_MODE)
public void setLineBreakMode(ReactTextView view, @Nullable String ellipsizeMode) {
if(ellipsizeMode == null) {

View File

@ -119,7 +119,14 @@ public class ReactTextInputShadowNode extends ReactTextShadowNode implements
if (mJsEventCount != UNSET) {
Spannable preparedSpannableText = fromTextCSSNode(this);
ReactTextUpdate reactTextUpdate =
new ReactTextUpdate(preparedSpannableText, mJsEventCount, mContainsImages, getPadding(), getEffectiveLineHeight());
new ReactTextUpdate(
preparedSpannableText,
mJsEventCount,
mContainsImages,
getPadding(),
getEffectiveLineHeight(),
mTextAlign
);
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}